use std::path::{Path, PathBuf};
use clap::{Args, Parser, Subcommand};
pub(crate) const DEFAULT_ENVIRONMENT: &str = "demo";
#[derive(Debug, Parser)]
#[command(
name = "icydb",
about = "Developer CLI tools for IcyDB",
long_about = None
)]
pub(crate) struct CliArgs {
#[command(subcommand)]
pub(crate) command: CliCommand,
}
#[derive(Debug, Subcommand)]
pub(crate) enum CliCommand {
Sql(SqlArgs),
Snapshot(CanisterTarget),
Metrics(MetricsArgs),
Schema(CanisterTarget),
#[command(subcommand)]
Config(ConfigCommand),
#[command(subcommand)]
Canister(CanisterCommand),
}
#[derive(Args, Debug)]
#[command(trailing_var_arg = true)]
pub(crate) struct SqlArgs {
#[arg(short, long, required = true)]
pub(crate) canister: String,
#[arg(short, long, env = "ICP_ENVIRONMENT", default_value = DEFAULT_ENVIRONMENT)]
pub(crate) environment: String,
#[arg(long, default_value = ".cache/sql_history")]
pub(crate) history_file: PathBuf,
#[arg(long, conflicts_with = "trailing_sql")]
pub(crate) sql: Option<String>,
#[arg(value_name = "SQL", allow_hyphen_values = true)]
pub(crate) trailing_sql: Vec<String>,
}
#[derive(Args, Clone, Debug)]
pub(crate) struct CanisterTarget {
#[arg(value_name = "CANISTER")]
pub(crate) canister: String,
#[arg(short, long, env = "ICP_ENVIRONMENT", default_value = DEFAULT_ENVIRONMENT)]
pub(crate) environment: String,
}
impl CanisterTarget {
pub(crate) const fn canister_name(&self) -> &str {
self.canister.as_str()
}
pub(crate) const fn environment(&self) -> &str {
self.environment.as_str()
}
}
#[derive(Args, Clone, Debug)]
pub(crate) struct EnvironmentTarget {
#[arg(short, long, env = "ICP_ENVIRONMENT", default_value = DEFAULT_ENVIRONMENT)]
pub(crate) environment: String,
}
impl EnvironmentTarget {
pub(crate) const fn environment(&self) -> &str {
self.environment.as_str()
}
}
#[derive(Args, Debug)]
pub(crate) struct MetricsArgs {
#[command(flatten)]
pub(crate) target: CanisterTarget,
#[arg(long, conflicts_with = "reset")]
pub(crate) window_start_ms: Option<u64>,
#[arg(long)]
pub(crate) reset: bool,
}
impl MetricsArgs {
pub(crate) const fn target(&self) -> &CanisterTarget {
&self.target
}
pub(crate) const fn window_start_ms(&self) -> Option<u64> {
self.window_start_ms
}
pub(crate) const fn reset(&self) -> bool {
self.reset
}
}
#[derive(Debug, Subcommand)]
pub(crate) enum ConfigCommand {
Init(ConfigInitArgs),
Show(ConfigArgs),
Check(ConfigArgs),
}
#[derive(Args, Clone, Debug)]
pub(crate) struct ConfigArgs {
#[arg(long)]
pub(crate) start_dir: Option<PathBuf>,
#[arg(short, long, env = "ICP_ENVIRONMENT")]
pub(crate) environment: Option<String>,
}
impl ConfigArgs {
pub(crate) fn environment(&self) -> Option<&str> {
self.environment.as_deref()
}
pub(crate) fn start_dir(&self) -> Option<&Path> {
self.start_dir.as_deref()
}
}
#[derive(Args, Clone, Debug)]
#[allow(
clippy::struct_excessive_bools,
reason = "clap flag bags intentionally mirror independent command-line switches"
)]
pub(crate) struct ConfigInitArgs {
#[arg(long)]
pub(crate) start_dir: Option<PathBuf>,
#[arg(short, long, required = true)]
pub(crate) canister: String,
#[arg(long)]
pub(crate) ddl: bool,
#[arg(long)]
pub(crate) fixtures: bool,
#[arg(long)]
pub(crate) metrics: bool,
#[arg(long = "metrics-reset")]
pub(crate) metrics_reset: bool,
#[arg(long)]
pub(crate) snapshot: bool,
#[arg(long)]
pub(crate) schema: bool,
#[arg(long)]
pub(crate) all: bool,
#[arg(long = "no-readonly")]
pub(crate) no_readonly: bool,
#[arg(long)]
pub(crate) force: bool,
}
impl ConfigInitArgs {
pub(crate) fn start_dir(&self) -> Option<&Path> {
self.start_dir.as_deref()
}
pub(crate) const fn canister_name(&self) -> &str {
self.canister.as_str()
}
pub(crate) const fn readonly(&self) -> bool {
!self.no_readonly
}
pub(crate) const fn ddl(&self) -> bool {
self.ddl || self.all
}
pub(crate) const fn fixtures(&self) -> bool {
self.fixtures || self.all
}
pub(crate) const fn metrics(&self) -> bool {
self.metrics || self.all
}
pub(crate) const fn metrics_reset(&self) -> bool {
self.metrics_reset || self.all
}
pub(crate) const fn snapshot(&self) -> bool {
self.snapshot || self.all
}
pub(crate) const fn schema(&self) -> bool {
self.schema || self.all
}
pub(crate) const fn force(&self) -> bool {
self.force
}
}
#[derive(Debug, Subcommand)]
pub(crate) enum CanisterCommand {
List(EnvironmentTarget),
Deploy(CanisterTarget),
Refresh(CanisterTarget),
Upgrade(UpgradeArgs),
Status(CanisterTarget),
}
#[derive(Args, Debug)]
pub(crate) struct UpgradeArgs {
#[command(flatten)]
pub(crate) target: CanisterTarget,
#[arg(long)]
pub(crate) wasm: Option<PathBuf>,
}