use std::ffi::OsString;
use std::path::PathBuf;
use clap::{CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
use crate::cli::branding::Branding;
#[derive(Debug, Parser)]
#[command(version)]
pub struct Cli {
#[arg(long, global = true)]
pub env: Option<String>,
#[command(subcommand)]
pub command: Command,
}
impl Cli {
pub fn command_for(branding: &Branding) -> clap::Command {
<Cli as CommandFactory>::command()
.name(branding.bin_name)
.bin_name(branding.bin_name)
.about(branding.about)
.after_help(crate::REVIEW_STATUS)
.mut_arg("env", |a| {
a.help(format!(
"Environment path, e.g. acme/dev (else {}, else the nearest {})",
branding.var("ENV"),
branding.dir_file
))
})
}
pub fn parse_with<I, T>(branding: &Branding, args: I) -> Cli
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let matches = Cli::command_for(branding).get_matches_from(args);
Cli::from_arg_matches(&matches).unwrap_or_else(|e| e.exit())
}
}
#[allow(rustdoc::invalid_html_tags)]
#[derive(Debug, Subcommand)]
pub enum Command {
Init {
project: String,
#[arg(long)]
server: String,
#[arg(long)]
kit: Option<PathBuf>,
},
#[command(subcommand)]
Env(EnvCommand),
#[command(subcommand)]
Key(KeyCommand),
Recover {
kit: PathBuf,
},
Set {
name: String,
},
Get {
name: String,
#[arg(long)]
version: Option<u64>,
},
Ls {
#[arg(long)]
all: bool,
},
History {
name: String,
},
Rm {
name: String,
},
#[command(subcommand)]
Config(ConfigCommand),
Run {
#[arg(long, value_delimiter = ',')]
only: Vec<String>,
#[arg(last = true, required = true, value_name = "COMMAND")]
command: Vec<OsString>,
},
Export {
#[arg(long, value_enum)]
format: Format,
#[arg(long)]
out: Option<PathBuf>,
#[arg(long)]
force: bool,
#[arg(long, value_delimiter = ',')]
only: Vec<String>,
},
#[command(subcommand)]
Token(TokenCommand),
Rotate,
Rekey {
path: Option<String>,
#[arg(long)]
kit: Option<PathBuf>,
#[arg(long)]
resume: bool,
#[arg(long)]
abort: bool,
},
Audit,
Status,
Ui {
#[arg(long)]
no_open: bool,
},
Mcp {
#[command(subcommand)]
command: Option<McpCommand>,
#[arg(long)]
config: Option<PathBuf>,
},
}
#[derive(Debug, Subcommand)]
pub enum ConfigCommand {
Set {
name: String,
#[arg(long, value_enum)]
format: ConfigFormatArg,
#[arg(long)]
file: Option<PathBuf>,
#[arg(long)]
allow_literals: bool,
},
Get {
name: String,
#[arg(long)]
version: Option<u64>,
},
Ls {
#[arg(long)]
all: bool,
},
History {
name: String,
},
Rm {
name: String,
},
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ConfigFormatArg {
Toml,
Json,
Yaml,
Text,
}
impl From<ConfigFormatArg> for crate::ConfigFormat {
fn from(f: ConfigFormatArg) -> Self {
match f {
ConfigFormatArg::Toml => Self::Toml,
ConfigFormatArg::Json => Self::Json,
ConfigFormatArg::Yaml => Self::Yaml,
ConfigFormatArg::Text => Self::Text,
}
}
}
#[derive(Debug, Subcommand)]
pub enum McpCommand {
Setup {
project: String,
#[arg(long)]
ttl: Option<String>,
},
}
#[derive(Debug, Subcommand)]
pub enum EnvCommand {
Add {
path: String,
},
Ls {
path: Option<String>,
},
Rm {
path: String,
#[arg(long)]
recursive: bool,
},
Repair {
path: String,
},
}
#[derive(Debug, Subcommand)]
pub enum KeyCommand {
Export {
path: String,
#[arg(long)]
out: Option<PathBuf>,
#[arg(long)]
yes: bool,
},
Import {
kit: PathBuf,
},
}
#[derive(Debug, Subcommand)]
pub enum TokenCommand {
Mint {
#[arg(long)]
scope: String,
#[arg(long)]
ttl: Option<String>,
#[arg(long, value_delimiter = ',')]
only: Vec<String>,
},
Ls,
Revoke {
id: String,
#[arg(long)]
rotate: bool,
},
Report {
#[arg(long)]
file: Option<PathBuf>,
#[arg(long)]
server: Option<String>,
},
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum Format {
Dotenv,
Json,
Yaml,
}