refactor: hand clap's own structs to the commands

This commit is contained in:
2026-09-09 12:37:19 +00:00
parent b40dfe6124
commit 5dbe99a304
8 changed files with 156 additions and 128 deletions

View File

@@ -2,64 +2,80 @@ use std::path::PathBuf;
use clap::{Args, Subcommand};
// each variant carries its own arguments as a struct rather than as fields
// spread across the enum. the command that implements it takes that struct, so
// main does not unpack what clap has already parsed and hand it on as a row of
// booleans nothing but position tells apart
#[derive(Subcommand, Debug)]
pub enum Link {
/// Move untracked paths into the store and symlink them back
Add {
/// Untracked or ignored paths inside the repository
#[arg(required = true)]
paths: Vec<PathBuf>,
/// Link to a store path that already exists
#[arg(long)]
force: bool,
#[command(flatten)]
store: Store,
},
Add(Add),
/// Move paths in the store back into the repository
Restore {
// said here rather than checked at runtime, so a mistake in the
// arguments is reported as one, with the usage and the exit code clap
// gives every other argument error
#[arg(required_unless_present = "all", conflicts_with = "all")]
paths: Vec<PathBuf>,
/// Restore every path this repository has in the store
#[arg(long)]
all: bool,
#[command(flatten)]
store: Store,
},
Restore(Restore),
/// List what this repository keeps in the store
List {
#[command(flatten)]
store: Store,
},
List(List),
/// List untracked paths a sandbox would still see
Check {
/// Limit the listing to these paths
paths: Vec<PathBuf>,
Check(Check),
}
/// Print `<code> <path>` for scripts, as `git status --porcelain` does
#[arg(long)]
porcelain: bool,
#[derive(Args, Debug)]
pub struct Add {
/// Untracked or ignored paths inside the repository
#[arg(required = true)]
pub paths: Vec<PathBuf>,
/// Exit with 4 when anything is outside the store, for scripts
#[arg(long)]
exit_code: bool,
/// Link to a store path that already exists
#[arg(long)]
pub force: bool,
/// Terminate porcelain entries with NUL
#[arg(short = 'z')]
null: bool,
#[command(flatten)]
pub store: Store,
}
#[command(flatten)]
store: Store,
},
#[derive(Args, Debug)]
pub struct Restore {
// said here rather than checked at runtime, so a mistake in the
// arguments is reported as one, with the usage and the exit code clap
// gives every other argument error
#[arg(required_unless_present = "all", conflicts_with = "all")]
pub paths: Vec<PathBuf>,
/// Restore every path this repository has in the store
#[arg(long)]
pub all: bool,
#[command(flatten)]
pub store: Store,
}
#[derive(Args, Debug)]
pub struct List {
#[command(flatten)]
pub store: Store,
}
#[derive(Args, Debug)]
pub struct Check {
/// Limit the listing to these paths
pub paths: Vec<PathBuf>,
/// Print `<code> <path>` for scripts, as `git status --porcelain` does
#[arg(long)]
pub porcelain: bool,
/// Exit with 4 when anything is outside the store, for scripts
#[arg(long)]
pub exit_code: bool,
/// Terminate porcelain entries with NUL
#[arg(short = 'z')]
pub null: bool,
#[command(flatten)]
pub store: Store,
}
#[derive(Args, Debug)]
@@ -70,3 +86,9 @@ pub struct Store {
#[arg(long = "store", env = "AHAB_LINK_ROOT", value_name = "DIR")]
pub root: Option<PathBuf>,
}
impl Store {
pub fn root(&self) -> Option<&std::path::Path> {
self.root.as_deref()
}
}