use clap::{ArgGroup, Args, Parser, Subcommand};
use crate::context::ColorChoice;
#[derive(Debug, Parser)]
#[command(
name = "dbmd",
version,
about = "The reference CLI for db.md — the open standard for databases in plain files.",
long_about = None,
propagate_version = true,
// Show the most useful help when invoked bare, rather than a terse error.
arg_required_else_help = true,
// We manage color ourselves via --color so output is pipe-safe by default.
disable_colored_help = true,
)]
pub struct Cli {
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true, value_enum, default_value_t = ColorChoice::Auto, value_name = "WHEN")]
pub color: ColorChoice,
#[command(subcommand)]
pub command: Command,
}
#[derive(Debug, Subcommand)]
pub enum Command {
Validate(ValidateArgs),
Format(FormatArgs),
Query(QueryArgs),
Show(ShowArgs),
Sections(SectionsArgs),
Schema(SchemaArgs),
Extract(ExtractArgs),
Search(SearchArgs),
Graph(GraphArgs),
Fm(FmArgs),
Body(BodyArgs),
Section(SectionArgs),
Tree(TreeArgs),
Stats(StatsArgs),
Emit(EmitArgs),
Outline(OutlineArgs),
Watch(WatchArgs),
Login(LoginArgs),
Logout(LogoutArgs),
Ask(AskArgs),
Do(AskArgs),
Build(AskArgs),
Api(ApiArgs),
Index(IndexArgs),
Log(LogArgs),
Write(WriteArgs),
Link(LinkArgs),
Rename(RenameArgs),
Rm(RmArgs),
Assets(AssetsArgs),
Resolve(ResolveArgs),
Sync(SyncArgs),
Grant(GrantArgs),
Propose(ProposeArgs),
Proposal(ProposalArgs),
Subscribe(SubscribeArgs),
Mirror(MirrorArgs),
Serve(ServeArgs),
Key(KeyArgs),
#[command(name = "__install-verified", hide = true)]
InstallVerified(InstallVerifiedArgs),
Spec(SpecArgs),
}
#[derive(Debug, Args)]
pub struct InstallVerifiedArgs {
#[arg(value_name = "SOURCE")]
pub source: String,
#[arg(value_name = "INSTALL_DIR")]
pub install_dir: String,
}
#[derive(Debug, Args)]
pub struct ValidateArgs {
#[arg(value_name = "DIR", default_value = ".")]
pub dir: String,
#[arg(long)]
pub all: bool,
#[arg(
long,
value_name = "FILE",
requires = "all",
conflicts_with = "projection_manifest"
)]
pub projection_excludes: Option<String>,
#[arg(
long,
value_name = "FILE",
requires = "all",
conflicts_with = "projection_excludes"
)]
pub projection_manifest: Option<String>,
#[arg(long, value_name = "RFC3339")]
pub since: Option<String>,
}
#[derive(Debug, Args)]
pub struct FormatArgs {
#[arg(value_name = "FILE")]
pub file: String,
}
#[derive(Debug, Args)]
pub struct QueryArgs {
#[arg(long, value_name = "TYPE")]
pub r#type: Option<String>,
#[arg(long, value_name = "LAYER")]
pub r#in: Option<String>,
#[arg(long = "where", value_name = "K=V")]
pub r#where: Vec<String>,
#[arg(long, value_name = "RFC3339")]
pub updated_after: Option<String>,
#[arg(long, value_name = "RFC3339")]
pub updated_before: Option<String>,
#[arg(long, value_name = "RFC3339")]
pub created_after: Option<String>,
#[arg(long, value_name = "RFC3339")]
pub created_before: Option<String>,
#[arg(long, value_name = "N")]
pub limit: Option<usize>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ShowArgs {
#[arg(value_name = "FILE")]
pub file: String,
}
#[derive(Debug, Args)]
pub struct SectionsArgs {
#[arg(value_name = "FILE")]
pub file: String,
}
#[derive(Debug, Args)]
pub struct SchemaArgs {
#[arg(value_name = "TYPE")]
pub r#type: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ExtractArgs {
#[arg(value_name = "FILE")]
pub file: String,
#[arg(long, value_name = "PATH")]
pub out: Option<String>,
}
#[derive(Debug, Args)]
pub struct SearchArgs {
#[arg(value_name = "QUERY")]
pub query: String,
#[arg(long, value_name = "TYPE")]
pub r#type: Option<String>,
#[arg(long, value_name = "LAYER")]
pub r#in: Option<String>,
#[arg(long = "where", value_name = "K=V")]
pub r#where: Vec<String>,
#[arg(long, value_name = "PATH")]
pub linked_from: Option<String>,
#[arg(long, value_name = "PATH")]
pub linked_to: Option<String>,
#[arg(long, value_name = "RFC3339")]
pub updated_after: Option<String>,
#[arg(long, value_name = "RFC3339")]
pub updated_before: Option<String>,
#[arg(long, value_name = "RFC3339")]
pub created_after: Option<String>,
#[arg(long, value_name = "RFC3339")]
pub created_before: Option<String>,
#[arg(long, value_name = "N")]
pub limit: Option<usize>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct GraphArgs {
#[command(subcommand)]
pub command: GraphCommand,
}
#[derive(Debug, Subcommand)]
pub enum GraphCommand {
Backlinks(GraphTargetArgs),
Forwardlinks(GraphTargetArgs),
Neighborhood(NeighborhoodArgs),
Orphans(OrphansArgs),
}
#[derive(Debug, Args)]
pub struct GraphTargetArgs {
#[arg(value_name = "PATH")]
pub path: String,
#[arg(long, value_name = "TYPE")]
pub r#type: Option<String>,
#[arg(long, value_name = "LAYER")]
pub r#in: Option<String>,
#[arg(long, value_name = "N")]
pub limit: Option<usize>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct NeighborhoodArgs {
#[arg(value_name = "SEED")]
pub seed: String,
#[arg(long, value_name = "N", default_value_t = 1)]
pub hops: usize,
#[arg(long, value_name = "TYPE")]
pub r#type: Option<String>,
#[arg(long, value_name = "LAYER")]
pub r#in: Option<String>,
#[arg(long, value_name = "N")]
pub limit: Option<usize>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct OrphansArgs {
#[arg(long, value_name = "LAYER")]
pub r#in: Option<String>,
#[arg(long, value_name = "N")]
pub limit: Option<usize>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct FmArgs {
#[command(subcommand)]
pub command: FmCommand,
}
#[derive(Debug, Subcommand)]
pub enum FmCommand {
Get(FmGetArgs),
Set(FmSetArgs),
Init(FmInitArgs),
}
#[derive(Debug, Args)]
pub struct FmGetArgs {
#[arg(value_name = "FILE")]
pub file: String,
#[arg(value_name = "KEY")]
pub key: String,
}
#[derive(Debug, Args)]
pub struct FmSetArgs {
#[arg(value_name = "FILE")]
pub file: String,
#[arg(value_name = "K=V")]
pub assignment: String,
}
#[derive(Debug, Args)]
pub struct FmInitArgs {
#[arg(value_name = "FILE")]
pub file: String,
#[arg(long, value_name = "STR")]
pub summary: Option<String>,
}
#[derive(Debug, Args)]
pub struct TreeArgs {
#[arg(long, value_name = "LAYER")]
pub layer: Option<String>,
#[arg(long, value_name = "TYPE")]
pub r#type: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct StatsArgs {
#[arg(value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct EmitArgs {
#[arg(value_name = "DIR", default_value = ".")]
pub dir: String,
#[arg(long)]
pub ndjson: bool,
}
#[derive(Debug, Args)]
pub struct OutlineArgs {
#[arg(value_name = "FILE")]
pub file: String,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct IndexArgs {
#[command(subcommand)]
pub command: IndexCommand,
}
#[derive(Debug, Subcommand)]
pub enum IndexCommand {
Rebuild(IndexRebuildArgs),
Show(IndexShowArgs),
}
#[derive(Debug, Args)]
pub struct IndexRebuildArgs {
#[arg(long, value_name = "LAYER")]
pub layer: Option<String>,
#[arg(long, value_name = "PATH")]
pub folder: Option<String>,
#[arg(long)]
pub dry_run: bool,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct IndexShowArgs {
#[arg(value_name = "PATH")]
pub path: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct LogArgs {
#[command(subcommand)]
pub command: LogCommand,
}
#[derive(Debug, Subcommand)]
pub enum LogCommand {
Tail(LogTailArgs),
Since(LogSinceArgs),
#[command(external_subcommand)]
Append(Vec<String>),
}
#[derive(Debug, Args)]
pub struct LogTailArgs {
#[arg(value_name = "N", default_value_t = 20)]
pub n: usize,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct LogSinceArgs {
#[arg(value_name = "RFC3339")]
pub timestamp: String,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct WriteArgs {
#[arg(value_name = "PATH")]
pub path: String,
#[arg(long, value_name = "TYPE")]
pub r#type: String,
#[arg(long, value_name = "STR")]
pub summary: Option<String>,
#[arg(long, value_name = "K=V")]
pub fm: Vec<String>,
#[arg(long, value_name = "PATH")]
pub body_file: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct LinkArgs {
#[arg(value_name = "FROM")]
pub from: String,
#[arg(value_name = "TO")]
pub to: String,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct RenameArgs {
#[arg(value_name = "OLD")]
pub old: String,
#[arg(value_name = "NEW")]
pub new: String,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ApiArgs {
#[arg(long, value_name = "ADDR", default_value = "127.0.0.1:3263")]
pub addr: String,
#[arg(long = "ask")]
pub enable_ask: bool,
#[arg(long = "do")]
pub enable_do: bool,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct LoginArgs {
#[arg(value_name = "PROVIDER")]
pub provider: Option<String>,
#[arg(long)]
pub code: bool,
#[arg(long)]
pub status: bool,
}
#[derive(Debug, Args)]
pub struct LogoutArgs {
#[arg(value_name = "PROVIDER")]
pub provider: Option<String>,
}
#[derive(Debug, Args)]
pub struct AskArgs {
#[arg(value_name = "PROMPT")]
pub prompt: String,
#[arg(long, value_name = "NAME")]
pub provider: Option<String>,
#[arg(long, value_name = "MODEL")]
pub model: Option<String>,
#[arg(long, value_name = "URL")]
pub base_url: Option<String>,
#[arg(long, value_name = "PROTO")]
pub protocol: Option<String>,
#[arg(long, value_name = "LEVEL")]
pub effort: Option<String>,
#[arg(long, value_name = "N", default_value_t = 15)]
pub max_turns: usize,
#[arg(long, value_name = "N")]
pub max_tokens: Option<u32>,
#[arg(long, value_name = "DIR")]
pub workspace: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct WatchArgs {
#[arg(long, value_name = "PATH")]
pub path: Option<String>,
#[arg(long, value_name = "SECS", default_value_t = 1)]
pub interval: u64,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct BodyArgs {
#[command(subcommand)]
pub command: BodyCommand,
}
#[derive(Debug, Subcommand)]
pub enum BodyCommand {
Set(BodyEditArgs),
Append(BodyEditArgs),
}
#[derive(Debug, Args)]
#[command(group = ArgGroup::new("content").required(true).args(["text", "body_file"]))]
pub struct BodyEditArgs {
#[arg(value_name = "FILE")]
pub file: String,
#[arg(long, value_name = "TEXT", allow_hyphen_values = true)]
pub text: Option<String>,
#[arg(long, value_name = "PATH")]
pub body_file: Option<String>,
}
#[derive(Debug, Args)]
pub struct SectionArgs {
#[command(subcommand)]
pub command: SectionCommand,
}
#[derive(Debug, Subcommand)]
pub enum SectionCommand {
Get(SectionGetArgs),
Set(SectionEditArgs),
Append(SectionEditArgs),
}
#[derive(Debug, Args)]
pub struct SectionGetArgs {
#[arg(value_name = "FILE")]
pub file: String,
#[arg(value_name = "HEADING")]
pub heading: String,
}
#[derive(Debug, Args)]
#[command(group = ArgGroup::new("content").required(true).args(["text", "body_file"]))]
pub struct SectionEditArgs {
#[arg(value_name = "FILE")]
pub file: String,
#[arg(value_name = "HEADING")]
pub heading: String,
#[arg(long, value_name = "TEXT", allow_hyphen_values = true)]
pub text: Option<String>,
#[arg(long, value_name = "PATH")]
pub body_file: Option<String>,
#[arg(long)]
pub create: bool,
#[arg(long, value_name = "N", default_value_t = 2,
value_parser = clap::value_parser!(u8).range(2..=6))]
pub level: u8,
}
#[derive(Debug, Args)]
pub struct RmArgs {
#[arg(value_name = "PATH")]
pub path: String,
#[arg(long)]
pub force: bool,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct SpecArgs {
#[arg(long, value_name = "PATH")]
pub spec: Option<String>,
}
#[derive(Debug, Args)]
pub struct AssetsArgs {
#[command(subcommand)]
pub command: AssetsCommand,
}
#[derive(Debug, Subcommand)]
pub enum AssetsCommand {
Scan(AssetsScanArgs),
Refresh(AssetsRefreshArgs),
#[command(name = "refresh-wrapper")]
RefreshWrapper(AssetsRefreshWrapperArgs),
Verify(AssetsVerifyArgs),
Status(AssetsStatusArgs),
Paths(AssetsPathsArgs),
}
#[derive(Debug, Args)]
pub struct AssetsScanArgs {
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub untracked: bool,
}
#[derive(Debug, Args)]
pub struct AssetsRefreshArgs {
#[arg(value_name = "PATH")]
pub path: String,
#[arg(long, value_name = "PATH")]
pub wrapper: String,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct AssetsRefreshWrapperArgs {
#[arg(value_name = "WRAPPER")]
pub wrapper: String,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct AssetsVerifyArgs {
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
#[arg(long)]
pub include_optional: bool,
#[arg(long)]
pub quick: bool,
#[arg(long, value_name = "FILE", conflicts_with = "projection_manifest")]
pub projection_excludes: Option<String>,
#[arg(long, value_name = "FILE", conflicts_with = "projection_excludes")]
pub projection_manifest: Option<String>,
}
#[derive(Debug, Args)]
pub struct AssetsStatusArgs {
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct AssetsPathsArgs {
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ResolveArgs {
#[arg(value_name = "ADDRESS")]
pub address: String,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct SyncArgs {
#[arg(value_name = "BRAIN")]
pub brain: Option<String>,
#[command(subcommand)]
pub action: Option<SyncAction>,
#[arg(long, alias = "push-only")]
pub push: bool,
#[arg(long, conflicts_with = "push")]
pub pull_only: bool,
#[arg(long, conflicts_with = "pull_only")]
pub resume_local_policy: bool,
#[arg(long, value_name = "ID:DIGEST", conflicts_with = "pull_only")]
pub confirm_bulk: Option<String>,
#[arg(
long,
value_name = "PATH",
action = clap::ArgAction::Append,
requires = "withdraw_reason",
conflicts_with = "pull_only"
)]
pub withdraw_from_hosting: Vec<String>,
#[arg(
long,
value_name = "REASON",
requires = "withdraw_from_hosting",
conflicts_with = "pull_only"
)]
pub withdraw_reason: Option<String>,
#[arg(
long,
value_name = "DIR",
conflicts_with_all = [
"push",
"resume_local_policy",
"confirm_bulk",
"withdraw_from_hosting",
"withdraw_reason"
]
)]
pub out: Option<String>,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Subcommand)]
pub enum SyncAction {
Rebind(SyncRebindArgs),
Relocate(SyncRelocateArgs),
Resolve(SyncResolveArgs),
Conflicts(SyncConflictsArgs),
}
#[derive(Debug, Args)]
pub struct SyncRelocateArgs {
#[arg(long, value_name = "OLD_DIR")]
pub from: String,
#[arg(long, value_name = "NEW_DIR")]
pub to: String,
}
#[derive(Debug, Args)]
pub struct SyncRebindArgs {
#[arg(long, value_name = "OLD_BRAIN_ULID")]
pub from: String,
#[arg(long, value_name = "NEW_BRAIN_ULID")]
pub to: String,
}
#[derive(Debug, Args)]
pub struct SyncConflictsArgs {
#[arg(long)]
pub prune: bool,
#[arg(long, requires = "prune")]
pub all: bool,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct SyncResolveArgs {
#[arg(value_name = "BUNDLE")]
pub bundle: String,
#[arg(
long,
required_unless_present_any = ["take_remote", "from"],
conflicts_with_all = ["take_remote", "from"]
)]
pub keep_local: bool,
#[arg(long, conflicts_with = "from")]
pub take_remote: bool,
#[arg(long, value_name = "SAFE_FILE")]
pub from: Option<String>,
#[arg(long, value_name = "ID:DIGEST")]
pub confirm_bulk: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
}
#[derive(Debug, Args)]
pub struct GrantArgs {
#[command(subcommand)]
pub command: GrantCommand,
}
#[derive(Debug, Subcommand)]
pub enum GrantCommand {
Issue(GrantIssueArgs),
List(GrantListArgs),
Revoke(GrantRevokeArgs),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum GrantCapability {
Read,
Write,
}
#[derive(Debug, Args)]
pub struct GrantIssueArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(value_name = "GRANTEE")]
pub grantee: String,
#[arg(long, value_enum, default_value_t = GrantCapability::Read, value_name = "CAP")]
pub can: GrantCapability,
#[arg(long, value_name = "PREFIX")]
pub scope: Option<String>,
#[arg(long, value_name = "ISO8601")]
pub until: Option<String>,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct GrantListArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct GrantRevokeArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(value_name = "GRANT_ID")]
pub grant_id: String,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ProposeArgs {
#[arg(value_name = "SITE")]
pub site: String,
#[arg(long, value_name = "SLUG")]
pub app: String,
#[arg(long, value_name = "TEXT", conflicts_with = "body_file")]
pub body: Option<String>,
#[arg(long, value_name = "PATH")]
pub body_file: Option<String>,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ProposalArgs {
#[command(subcommand)]
pub command: ProposalCommand,
}
#[derive(Debug, Subcommand)]
pub enum ProposalCommand {
List(ProposalListArgs),
Show(ProposalTargetArgs),
Accept(ProposalDecisionArgs),
Reject(ProposalDecisionArgs),
}
#[derive(Debug, Args)]
pub struct ProposalListArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(long, default_value = "pending", value_name = "STATE")]
pub state: String,
#[arg(long, value_name = "CURSOR")]
pub after: Option<String>,
#[arg(long, default_value_t = 50, value_name = "N")]
pub limit: usize,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ProposalTargetArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(value_name = "PROPOSAL_ID")]
pub proposal_id: String,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ProposalDecisionArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(value_name = "PROPOSAL_ID")]
pub proposal_id: String,
#[arg(long, value_name = "ID")]
pub mutation_id: String,
#[arg(long, value_name = "TEXT")]
pub reason: String,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct SubscribeArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(long, value_name = "SEQ")]
pub since: Option<u64>,
#[arg(long, value_name = "SECS", default_value_t = 30)]
pub interval: u64,
#[arg(long)]
pub once: bool,
#[arg(long, value_name = "URL")]
pub hub: Option<String>,
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct KeyArgs {
#[command(subcommand)]
pub command: KeyCommand,
}
#[derive(Debug, Subcommand)]
pub enum KeyCommand {
Generate(KeyGenerateArgs),
Rotate(KeyRotateArgs),
}
#[derive(Debug, Args)]
pub struct KeyGenerateArgs {
#[arg(long, value_name = "FILE")]
pub out: String,
}
#[derive(Debug, Args)]
pub struct MirrorArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(long, value_name = "DIR")]
pub dir: String,
}
#[derive(Debug, Args)]
pub struct ServeArgs {
#[arg(long, value_name = "DIR", default_value = ".")]
pub dir: String,
#[arg(long, value_name = "ED25519:MULTIKEY")]
pub pin: String,
#[arg(long, value_name = "ADDR", default_value = "127.0.0.1:0")]
pub addr: String,
#[arg(long)]
pub unsafe_public: bool,
}
#[derive(Debug, Args)]
pub struct KeyRotateArgs {
#[arg(value_name = "BRAIN")]
pub brain: String,
#[arg(long, value_name = "FILE")]
pub key_file: String,
#[arg(long, value_name = "FILE")]
pub out: String,
}
#[cfg(test)]
mod tests {
use super::*;
const OLD: &str = "01j5qc3v9k4ym8rwbn2tqe6f7d";
const NEW: &str = "01j5qc3v9k4ym8rwbn2tqe6f7e";
#[test]
fn sync_parses_exact_withdrawal_intent_and_reason() {
let cli = Cli::try_parse_from([
"dbmd",
"sync",
"company",
"--push",
"--withdraw-from-hosting",
"sources/private/a.md",
"--withdraw-from-hosting",
"assets/private.pdf",
"--withdraw-reason",
"approved retention change",
])
.unwrap();
let Command::Sync(args) = cli.command else {
panic!("expected sync");
};
assert_eq!(
args.withdraw_from_hosting,
["sources/private/a.md", "assets/private.pdf"]
);
assert_eq!(
args.withdraw_reason.as_deref(),
Some("approved retention change")
);
}
#[test]
fn sync_withdrawal_requires_a_reason() {
assert!(Cli::try_parse_from([
"dbmd",
"sync",
"company",
"--withdraw-from-hosting",
"sources/private/a.md",
])
.is_err());
}
#[test]
fn sync_parses_the_fail_closed_alias_rebind_shape() {
let cli = Cli::try_parse_from([
"dbmd", "sync", "company", "rebind", "--from", OLD, "--to", NEW,
])
.unwrap();
let Command::Sync(args) = cli.command else {
panic!("expected sync");
};
let Some(SyncAction::Rebind(rebind)) = args.action else {
panic!("expected rebind");
};
assert_eq!(rebind.from, OLD);
assert_eq!(rebind.to, NEW);
}
#[test]
fn sync_parses_the_checkout_relocation_shape() {
let cli = Cli::try_parse_from([
"dbmd",
"sync",
OLD,
"relocate",
"--from",
"/tmp/stage/db",
"--to",
"/tmp/live/db",
])
.unwrap();
let Command::Sync(args) = cli.command else {
panic!("expected sync");
};
let Some(SyncAction::Relocate(relocate)) = args.action else {
panic!("expected relocate");
};
assert_eq!(relocate.from, "/tmp/stage/db");
assert_eq!(relocate.to, "/tmp/live/db");
}
}