use std::collections::HashMap;
use anyhow::Result;
use app::AppCliCommand;
use build::BuildCommand;
use call::CallCli;
use clap::{Parser, Subcommand};
use completions::CompletionOpts;
use ctl::CtlCliCommand;
use ctx::CtxCommand;
use down::DownCommand;
use generate::NewCliCommand;
use keys::KeysCliCommand;
use par::ParCliCommand;
use reg::RegCliCommand;
use serde_json::json;
use smithy::{GenerateCli, LintCli, ValidateCli};
use up::UpCommand;
use wash_lib::cli::claims::ClaimsCliCommand;
use wash_lib::cli::inspect::InspectCliCommand;
use wash_lib::cli::{CommandOutput, OutputKind};
use wash_lib::drain::Drain as DrainSelection;
mod app;
mod appearance;
mod build;
mod call;
mod cfg;
mod completions;
mod ctl;
mod ctx;
mod down;
mod drain;
mod generate;
mod keys;
mod par;
mod reg;
mod smithy;
mod up;
mod util;
const HELP: &str = r#"
_________________________________________________________________________________
_____ _ _ _____ _ _ _
/ ____| | | | / ____| | | | |
__ ____ _ ___ _ __ ___ | | | | ___ _ _ __| | | (___ | |__ ___| | |
\ \ /\ / / _` / __| '_ ` _ \| | | |/ _ \| | | |/ _` | \___ \| '_ \ / _ \ | |
\ V V / (_| \__ \ | | | | | |____| | (_) | |_| | (_| | ____) | | | | __/ | |
\_/\_/ \__,_|___/_| |_| |_|\_____|_|\___/ \__,_|\__,_| |_____/|_| |_|\___|_|_|
_________________________________________________________________________________
Interact and manage wasmCloud applications, projects, and runtime environments
Usage: wash [OPTIONS] <COMMAND>
Applications:
app Manage declarative applications and deployments (wadm) (experimental)
call Invoke a wasmCloud actor
ctl Interact with a wasmCloud control interface
Projects:
build Build (and sign) a wasmCloud actor, provider, or interface
claims Generate and manage JWTs for wasmCloud actors
gen Generate code from smithy IDL files
inspect Inspect capability provider or actor module
lint Perform lint checks on smithy models
new Create a new project from template
par Create, inspect, and modify capability provider archive files
reg Push an actor or provider component to an OCI or Bindle registry
validate Perform validation checks on smithy models
Configuration:
completions Generate shell completions
ctx Manage wasmCloud host configuration contexts
drain Manage contents of local wasmCloud caches
keys Utilities for generating and managing keys
Runtime environments:
up Bootstrap a wasmCloud environment
down Tear down a wasmCloud environment launched with wash up
Options:
-o, --output <OUTPUT> Specify output format (text or json) [default: text]
-h, --help Print help
-V, --version Print version
"#;
#[derive(Debug, Clone, Parser)]
#[clap(name = "wash", version, override_help = HELP)]
struct Cli {
#[clap(
short = 'o',
long = "output",
default_value = "text",
help = "Specify output format (text or json)",
global = true
)]
pub(crate) output: OutputKind,
#[clap(subcommand)]
command: CliCommand,
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Subcommand)]
enum CliCommand {
#[clap(name = "app", subcommand)]
App(AppCliCommand),
#[clap(name = "build")]
Build(BuildCommand),
#[clap(name = "call")]
Call(CallCli),
#[clap(name = "completions")]
Completions(CompletionOpts),
#[clap(name = "claims", subcommand)]
Claims(ClaimsCliCommand),
#[clap(name = "ctl", subcommand)]
Ctl(CtlCliCommand),
#[clap(name = "ctx", subcommand)]
Ctx(CtxCommand),
#[clap(name = "down")]
Down(DownCommand),
#[clap(name = "drain", subcommand)]
Drain(DrainSelection),
#[clap(name = "gen")]
Gen(GenerateCli),
#[clap(name = "inspect")]
Inspect(InspectCliCommand),
#[clap(name = "keys", subcommand)]
Keys(KeysCliCommand),
#[clap(name = "lint")]
Lint(LintCli),
#[clap(name = "new", subcommand)]
New(NewCliCommand),
#[clap(name = "par", subcommand)]
Par(ParCliCommand),
#[clap(name = "reg", subcommand)]
Reg(RegCliCommand),
#[clap(name = "up")]
Up(UpCommand),
#[clap(name = "validate")]
Validate(ValidateCli),
}
#[tokio::main]
async fn main() {
use clap::CommandFactory;
if env_logger::try_init().is_err() {}
let cli: Cli = Parser::parse();
let output_kind = cli.output;
let res: Result<CommandOutput> = match cli.command {
CliCommand::App(app_cli) => app::handle_command(app_cli, output_kind).await,
CliCommand::Build(build_cli) => build::handle_command(build_cli),
CliCommand::Call(call_cli) => call::handle_command(call_cli.command()).await,
CliCommand::Claims(claims_cli) => {
wash_lib::cli::claims::handle_command(claims_cli, output_kind).await
}
CliCommand::Completions(completions_cli) => {
completions::handle_command(completions_cli, Cli::command())
}
CliCommand::Ctl(ctl_cli) => ctl::handle_command(ctl_cli, output_kind).await,
CliCommand::Ctx(ctx_cli) => ctx::handle_command(ctx_cli).await,
CliCommand::Down(down_cli) => down::handle_command(down_cli, output_kind).await,
CliCommand::Drain(drain_cli) => drain::handle_command(drain_cli),
CliCommand::Gen(generate_cli) => smithy::handle_gen_command(generate_cli),
CliCommand::Inspect(inspect_cli) => {
wash_lib::cli::inspect::handle_command(inspect_cli, output_kind).await
}
CliCommand::Keys(keys_cli) => keys::handle_command(keys_cli),
CliCommand::Lint(lint_cli) => smithy::handle_lint_command(lint_cli).await,
CliCommand::New(new_cli) => generate::handle_command(new_cli).await,
CliCommand::Par(par_cli) => par::handle_command(par_cli, output_kind).await,
CliCommand::Reg(reg_cli) => reg::handle_command(reg_cli, output_kind).await,
CliCommand::Up(up_cli) => up::handle_command(up_cli, output_kind).await,
CliCommand::Validate(validate_cli) => smithy::handle_validate_command(validate_cli).await,
};
std::process::exit(match res {
Ok(out) => {
match output_kind {
OutputKind::Json => {
let mut map = out.map;
map.insert("success".to_string(), json!(true));
println!("\n{}", serde_json::to_string_pretty(&map).unwrap());
0
}
OutputKind::Text => {
println!("\n{}", out.text);
match completions::first_run_suggestion() {
Ok(Some(suggestion)) => {
println!("\n{}", suggestion);
0
}
Ok(None) => {
0
}
Err(e) => {
eprintln!("\nError: {}", e);
1
}
}
}
}
}
Err(e) => {
match output_kind {
OutputKind::Json => {
let mut map = HashMap::new();
map.insert("success".to_string(), json!(false));
map.insert("error".to_string(), json!(e.to_string()));
let error_chain = e
.chain()
.skip(1)
.map(|e| format!("{e}"))
.collect::<Vec<String>>();
if !error_chain.is_empty() {
map.insert("error_chain".to_string(), json!(error_chain));
}
let backtrace = e.backtrace().to_string();
if !backtrace.is_empty() && backtrace != "disabled backtrace" {
map.insert("backtrace".to_string(), json!(backtrace));
}
eprintln!("\n{}", serde_json::to_string_pretty(&map).unwrap());
}
OutputKind::Text => {
eprintln!("\n{e:?}");
}
}
1
}
})
}