mirror of
https://github.com/NotAShelf/stash.git
synced 2026-04-12 22:17:41 +00:00
cli: add db subcommand
Adds a `db` subcommand with `DbAction` for three new database operations: wipe, vacuum and stats. We can extend this database later, but this is a very good start for now and plays nicely with the `--expired` flag. This soft-deprecates `stash wipe` in favor of a `stash db wipe` with the addition of a new `--expired` flag that wipes the expired entries only. The `list` subcommand has also been refactored to allow for a similar `--expired` flag that lists only expired entries. Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I34107880185d231d207b0dab7782d5d96a6a6964
This commit is contained in:
parent
2e555ee043
commit
5731fb08a5
1 changed files with 118 additions and 56 deletions
124
src/main.rs
124
src/main.rs
|
|
@ -99,12 +99,21 @@ enum Command {
|
|||
},
|
||||
|
||||
/// Wipe all clipboard history
|
||||
///
|
||||
/// DEPRECATED: Use `stash db wipe` instead
|
||||
#[command(hide = true)]
|
||||
Wipe {
|
||||
/// Ask for confirmation before wiping
|
||||
#[arg(long)]
|
||||
ask: bool,
|
||||
},
|
||||
|
||||
/// Database management operations
|
||||
Db {
|
||||
#[command(subcommand)]
|
||||
action: DbAction,
|
||||
},
|
||||
|
||||
/// Import clipboard data from stdin (default: TSV format)
|
||||
Import {
|
||||
/// Explicitly specify format: "tsv" (default)
|
||||
|
|
@ -124,6 +133,26 @@ enum Command {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum DbAction {
|
||||
/// Wipe database entries
|
||||
Wipe {
|
||||
/// Only wipe expired entries instead of all entries
|
||||
#[arg(long)]
|
||||
expired: bool,
|
||||
|
||||
/// Ask for confirmation before wiping
|
||||
#[arg(long)]
|
||||
ask: bool,
|
||||
},
|
||||
|
||||
/// Optimize database using VACUUM
|
||||
Vacuum,
|
||||
|
||||
/// Show database statistics
|
||||
Stats,
|
||||
}
|
||||
|
||||
fn report_error<T>(
|
||||
result: Result<T, impl std::fmt::Display>,
|
||||
context: &str,
|
||||
|
|
@ -197,41 +226,15 @@ fn main() -> color_eyre::eyre::Result<()> {
|
|||
);
|
||||
},
|
||||
Some(Command::List { format, expired }) => {
|
||||
if expired {
|
||||
// Diagnostic mode: show expired entries only (does not cleanup)
|
||||
match db.get_expired_entries() {
|
||||
Ok(entries) => {
|
||||
for (id, contents, mime) in entries {
|
||||
let preview = db::preview_entry(
|
||||
&contents,
|
||||
mime.as_deref(),
|
||||
cli.preview_width,
|
||||
);
|
||||
println!("{id}\t{preview}");
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("failed to list expired entries: {e}");
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// Normal list mode
|
||||
// Cleanup expired entries when daemon is not running
|
||||
if let Ok(count) = db.cleanup_expired() {
|
||||
if count > 0 {
|
||||
log::info!("Cleaned up {} expired entries", count);
|
||||
}
|
||||
}
|
||||
|
||||
match format.as_deref() {
|
||||
Some("tsv") => {
|
||||
report_error(
|
||||
db.list(io::stdout(), cli.preview_width),
|
||||
db.list(io::stdout(), cli.preview_width, expired),
|
||||
"failed to list entries",
|
||||
);
|
||||
},
|
||||
Some("json") => {
|
||||
match db.list_json() {
|
||||
match db.list_json(expired) {
|
||||
Ok(json) => {
|
||||
println!("{json}");
|
||||
},
|
||||
|
|
@ -246,18 +249,17 @@ fn main() -> color_eyre::eyre::Result<()> {
|
|||
None => {
|
||||
if std::io::stdout().is_terminal() {
|
||||
report_error(
|
||||
db.list_tui(cli.preview_width),
|
||||
db.list_tui(cli.preview_width, expired),
|
||||
"failed to list entries in TUI",
|
||||
);
|
||||
} else {
|
||||
report_error(
|
||||
db.list(io::stdout(), cli.preview_width),
|
||||
db.list(io::stdout(), cli.preview_width, expired),
|
||||
"failed to list entries",
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(Command::Decode { input }) => {
|
||||
report_error(
|
||||
|
|
@ -324,6 +326,10 @@ fn main() -> color_eyre::eyre::Result<()> {
|
|||
}
|
||||
},
|
||||
Some(Command::Wipe { ask }) => {
|
||||
eprintln!(
|
||||
"Warning: The 'stash wipe' command is deprecated. Use 'stash db \
|
||||
wipe' instead."
|
||||
);
|
||||
let mut should_proceed = true;
|
||||
if ask {
|
||||
should_proceed = Confirm::new(
|
||||
|
|
@ -341,6 +347,62 @@ fn main() -> color_eyre::eyre::Result<()> {
|
|||
}
|
||||
},
|
||||
|
||||
Some(Command::Db { action }) => {
|
||||
match action {
|
||||
DbAction::Wipe { expired, ask } => {
|
||||
let mut should_proceed = true;
|
||||
if ask {
|
||||
let message = if expired {
|
||||
"Are you sure you want to wipe all expired clipboard entries?"
|
||||
} else {
|
||||
"Are you sure you want to wipe ALL clipboard history?"
|
||||
};
|
||||
should_proceed = Confirm::new(message)
|
||||
.with_default(false)
|
||||
.prompt()
|
||||
.unwrap_or(false);
|
||||
if !should_proceed {
|
||||
log::info!("db wipe command aborted by user.");
|
||||
}
|
||||
}
|
||||
if should_proceed {
|
||||
if expired {
|
||||
match db.cleanup_expired() {
|
||||
Ok(count) => {
|
||||
log::info!("Wiped {} expired entries", count);
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("failed to wipe expired entries: {e}");
|
||||
},
|
||||
}
|
||||
} else {
|
||||
report_error(db.wipe(), "failed to wipe database");
|
||||
}
|
||||
}
|
||||
},
|
||||
DbAction::Vacuum => {
|
||||
match db.vacuum() {
|
||||
Ok(()) => {
|
||||
log::info!("Database optimized successfully");
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("failed to vacuum database: {e}");
|
||||
},
|
||||
}
|
||||
},
|
||||
DbAction::Stats => {
|
||||
match db.stats() {
|
||||
Ok(stats) => {
|
||||
println!("{}", stats);
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("failed to get database stats: {e}");
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
Some(Command::Import { r#type, ask }) => {
|
||||
let mut should_proceed = true;
|
||||
if ask {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue