use std::path::PathBuf;
use crate::error::{FnoxError, Result};
use clap::{Parser, Subcommand};
use crate::config::Config;
pub mod activate;
pub mod check;
pub mod ci_redact;
pub mod completion;
pub mod config_files;
pub mod deactivate;
pub mod doctor;
pub mod edit;
pub mod exec;
pub mod export;
pub mod get;
pub mod hook_env;
pub mod import;
pub mod init;
pub mod lease;
pub mod list;
pub mod mcp;
pub mod profiles;
pub mod provider;
pub mod reencrypt;
pub mod remove;
pub mod scan;
pub mod schema;
pub mod set;
pub mod sync;
pub mod tui;
pub mod usage;
pub mod version;
#[derive(Parser)]
#[command(name = "fnox")]
#[command(about = "A flexible secret management tool by @jdx", long_about = None)]
#[command(version)]
#[command(help_expected = true)]
pub struct Cli {
#[arg(short, long, default_value = crate::config::DEFAULT_CONFIG_FILENAME, global = true)]
pub config: PathBuf,
#[arg(short = 'P', long, global = true)]
pub profile: Option<String>,
#[arg(short, long, global = true)]
pub verbose: bool,
#[arg(long, global = true, hide = true)]
pub age_key_file: Option<PathBuf>,
#[arg(long, global = true)]
pub if_missing: Option<String>,
#[arg(long, global = true)]
pub no_color: bool,
#[arg(long, global = true)]
pub no_defaults: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
Activate(activate::ActivateCommand),
Check(check::CheckCommand),
#[command(hide = true)]
CiRedact(ci_redact::CiRedactCommand),
Completion(completion::CompletionCommand),
ConfigFiles(config_files::ConfigFilesCommand),
Deactivate(deactivate::DeactivateCommand),
Doctor(doctor::DoctorCommand),
Edit(edit::EditCommand),
Exec(exec::ExecCommand),
Export(export::ExportCommand),
Get(get::GetCommand),
#[command(hide = true)]
HookEnv(hook_env::HookEnvCommand),
Import(import::ImportCommand),
Init(init::InitCommand),
Lease(lease::LeaseCommand),
List(list::ListCommand),
Mcp(mcp::McpCommand),
Profiles(profiles::ProfilesCommand),
Provider(provider::ProviderCommand),
Reencrypt(reencrypt::ReencryptCommand),
Remove(remove::RemoveCommand),
Scan(scan::ScanCommand),
#[command(hide = true)]
Schema(schema::SchemaCommand),
Set(set::SetCommand),
Sync(sync::SyncCommand),
Tui(tui::TuiCommand),
Usage(usage::UsageCommand),
Version(version::VersionCommand),
}
impl Commands {
pub async fn run(&self, cli: &Cli) -> Result<()> {
match self {
Commands::Version(cmd) => cmd.run(cli).await,
Commands::Init(cmd) => cmd.run(cli).await,
Commands::Completion(cmd) => cmd.run(cli).await,
Commands::ConfigFiles(cmd) => cmd.run(cli).await,
Commands::Schema(cmd) => cmd.run(cli).await,
Commands::Usage(cmd) => cmd.run(cli).await,
Commands::Activate(cmd) => cmd
.run()
.await
.map_err(|e| FnoxError::Config(e.to_string())),
Commands::Deactivate(cmd) => cmd
.run(cli, Config::new())
.await
.map_err(|e| FnoxError::Config(e.to_string())),
Commands::HookEnv(cmd) => cmd
.run()
.await
.map_err(|e| FnoxError::Config(e.to_string())),
Commands::Check(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::CiRedact(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Doctor(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Edit(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Export(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Get(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Import(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Lease(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::List(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Mcp(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Profiles(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Provider(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Reencrypt(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Remove(cmd) => cmd.run(cli).await,
Commands::Exec(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Set(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Sync(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Scan(cmd) => cmd.run(cli, self.load_config(cli)?).await,
Commands::Tui(cmd) => cmd.run(cli, self.load_config(cli)?).await,
}
}
fn load_config(&self, cli: &Cli) -> Result<Config> {
Config::load_smart(&cli.config)
}
}
#[cfg(test)]
mod tests {
use super::*;
use clap::CommandFactory;
#[test]
fn test_cli_ordering() {
clap_sort::assert_sorted(&Cli::command());
}
}