use std::env;
use std::process::Command;
use eyre::Result;
use namada_apps_lib::cli;
pub fn main() -> Result<()> {
let (cmd, raw_sub_cmd) = cli::namada_cli(namada_apps::namada_version());
handle_command(cmd, raw_sub_cmd)
}
fn handle_command(cmd: cli::cmds::Namada, raw_sub_cmd: String) -> Result<()> {
let args = env::args();
let is_bin_sub_cmd = matches!(
cmd,
cli::cmds::Namada::Node(_)
| cli::cmds::Namada::Client(_)
| cli::cmds::Namada::Relayer(_)
| cli::cmds::Namada::Wallet(_)
);
let mut sub_args: Vec<String> = args.skip(1).collect();
if is_bin_sub_cmd {
sub_args
.iter()
.position(|arg| arg == &raw_sub_cmd)
.map(|e| sub_args.remove(e));
}
match cmd {
cli::cmds::Namada::Node(_) | cli::cmds::Namada::Ledger(_) => {
handle_subcommand("namadan", sub_args)
}
cli::cmds::Namada::Client(_)
| cli::cmds::Namada::TxCustom(_)
| cli::cmds::Namada::TxTransparentTransfer(_)
| cli::cmds::Namada::TxShieldedTransfer(_)
| cli::cmds::Namada::TxShieldingTransfer(_)
| cli::cmds::Namada::TxUnshieldingTransfer(_)
| cli::cmds::Namada::TxIbcTransfer(_)
| cli::cmds::Namada::TxOsmosisSwap(_)
| cli::cmds::Namada::TxUpdateAccount(_)
| cli::cmds::Namada::TxRevealPk(_)
| cli::cmds::Namada::TxInitProposal(_)
| cli::cmds::Namada::TxVoteProposal(_) => {
handle_subcommand("namadac", sub_args)
}
cli::cmds::Namada::Wallet(_) => handle_subcommand("namadaw", sub_args),
cli::cmds::Namada::Relayer(_) | cli::cmds::Namada::EthBridgePool(_) => {
handle_subcommand("namadar", sub_args)
}
cli::cmds::Namada::Complete(cli::cmds::Complete(
cli::args::Complete { shell },
)) => {
use std::io::stdout;
use clap_complete::{generate, shells};
use clap_complete_nushell::Nushell;
let version = namada_apps::namada_version();
for (mut app, name) in [
(cli::namada_app(version), "namada"),
(cli::namada_node_app(version), "namadan"),
(cli::namada_client_app(version), "namadac"),
(cli::namada_wallet_app(version), "namadaw"),
(cli::namada_relayer_app(version), "namadar"),
] {
match shell {
cli::args::Shell::Bash => {
generate(shells::Bash, &mut app, name, &mut stdout())
}
cli::args::Shell::Elvish => {
generate(shells::Elvish, &mut app, name, &mut stdout())
}
cli::args::Shell::Fish => {
generate(shells::Fish, &mut app, name, &mut stdout())
}
cli::args::Shell::PowerShell => generate(
shells::PowerShell,
&mut app,
name,
&mut stdout(),
),
cli::args::Shell::Zsh => {
generate(shells::Zsh, &mut app, name, &mut stdout())
}
cli::args::Shell::Nushell => {
generate(Nushell, &mut app, name, &mut stdout())
}
};
}
Ok(())
}
}
}
fn handle_subcommand(program: &str, mut sub_args: Vec<String>) -> Result<()> {
let env_vars = env::vars_os();
let cmd_name = if env::var("CARGO").is_ok() {
let mut cargo_args =
vec!["run".to_string(), format!("--bin={}", program), "--".into()];
cargo_args.append(&mut sub_args);
sub_args = cargo_args;
"cargo".into()
} else {
let namada_path = env::current_exe()?;
namada_path.parent().unwrap().join(program)
};
let mut cmd = Command::new(cmd_name);
cmd.args(sub_args).envs(env_vars);
exec_subcommand(program, cmd)
}
pub fn exec_subcommand(program: &str, cmd: Command) -> Result<()> {
imp::exec_subcommand(program, cmd)
}
#[cfg(unix)]
mod imp {
use std::os::unix::process::CommandExt;
use std::process::Command;
use eyre::{eyre, Result};
pub fn exec_subcommand(program: &str, mut cmd: Command) -> Result<()> {
let error = cmd.exec();
Err(eyre!("Command {} failed with {}.", program, error))
}
}
#[cfg(windows)]
mod imp {
use std::process::Command;
use eyre::{eyre, Result, WrapErr};
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
use winapi::um::consoleapi::SetConsoleCtrlHandler;
unsafe extern "system" fn ctrlc_handler(_: DWORD) -> BOOL {
TRUE
}
pub fn exec_subcommand(program: &str, mut cmd: Command) -> Result<()> {
unsafe {
if SetConsoleCtrlHandler(Some(ctrlc_handler), TRUE) == FALSE {
return Err(eyre!("Could not set Ctrl-C handler."));
}
}
let exit = cmd
.status()
.wrap_err_with(|| eyre!("Could not execute command {}", program))?;
if exit.success() {
Ok(())
} else {
Err(eyre!("Command {} failed.", program))
}
}
}