implement kill command
This commit is contained in:
parent
f184d5b6a3
commit
63154cc1fc
|
@ -19,6 +19,7 @@ pub mod list;
|
|||
pub mod out;
|
||||
pub mod resume;
|
||||
pub mod backend;
|
||||
pub mod kill;
|
||||
|
||||
pub trait Command<'a> {
|
||||
type Args: TryFrom<&'a ArgMatches<'a>>;
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::io::{self, Write};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::database::Database;
|
||||
use crate::config::Config;
|
||||
|
||||
use super::Command;
|
||||
|
||||
fn read_line() -> String {
|
||||
let mut pre_n = String::new();
|
||||
io::stdin().read_line(&mut pre_n).unwrap();
|
||||
pre_n
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Args {
|
||||
Id(u64),
|
||||
Sheet(String),
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a ArgMatches<'a>> for Args {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(args: &'a ArgMatches) -> Result<Args> {
|
||||
Ok(args.value_of("id").map(|v| {
|
||||
Args::Id(v.parse().unwrap())
|
||||
}).unwrap_or_else(|| {
|
||||
Args::Sheet(args.value_of("sheet").unwrap().to_owned())
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KillCommand;
|
||||
|
||||
impl<'a> Command<'a> for KillCommand {
|
||||
type Args = Args;
|
||||
|
||||
fn handle<D, O, E>(args: Args, db: &mut D, out: &mut O, _err: &mut E, _config: &Config, _now: DateTime<Utc>) -> Result<()>
|
||||
where
|
||||
D: Database,
|
||||
O: Write,
|
||||
E: Write,
|
||||
{
|
||||
match args {
|
||||
Args::Id(id) => {
|
||||
if let Some(entry) = db.entry_by_id(id)? {
|
||||
writeln!(out, "are you sure you want to delete entry {}? ({}) [y/n]", entry.id, entry.note.unwrap_or("".into()))?;
|
||||
|
||||
if read_line().to_lowercase().starts_with("y") {
|
||||
db.delete_entry_by_id(id)?;
|
||||
writeln!(out, "It's dead")?;
|
||||
} else {
|
||||
writeln!(out, "Don't worry, it's still there")?;
|
||||
}
|
||||
} else {
|
||||
writeln!(out, "There's no entry with id {}. Someone found it before we did.", id)?;
|
||||
}
|
||||
},
|
||||
Args::Sheet(sheet) => {
|
||||
let n = db.entries_by_sheet(&sheet, None, None)?.len();
|
||||
|
||||
writeln!(out, "are you sure you want to delete {} entries on sheet \"{}\"?", n, sheet)?;
|
||||
|
||||
if read_line().to_lowercase().starts_with("y") {
|
||||
db.delete_entries_in_sheet(&sheet)?;
|
||||
writeln!(out, "They're gone")?;
|
||||
} else {
|
||||
writeln!(out, "Don't worry, they're still there")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -169,6 +169,22 @@ pub trait Database {
|
|||
Ok(self.entry_query("select * from entries where end is not null and sheet=?1 order by end desc limit 1", &[&sheet])?.into_iter().next())
|
||||
}
|
||||
|
||||
fn delete_entry_by_id(&mut self, id: u64) -> Result<()> {
|
||||
Ok(self.execute("delete from entries where id=?1", &[&id])?)
|
||||
}
|
||||
|
||||
fn delete_entries_in_sheet(&mut self, sheet: &str) -> Result<()> {
|
||||
self.execute("delete from entries where sheet=?1", &[&sheet])?;
|
||||
|
||||
if let Some(last) = self.last_sheet()? {
|
||||
if last == sheet {
|
||||
self.unset_last_sheet()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Meta queries
|
||||
fn current_sheet(&self) -> Result<Option<String>> {
|
||||
let results = self.meta_query("select * from meta where key='current_sheet'", &[])?;
|
||||
|
@ -196,6 +212,10 @@ pub trait Database {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn unset_last_sheet(&mut self) -> Result<()> {
|
||||
Ok(self.execute("delete from meta where key='last_sheet'", &[])?)
|
||||
}
|
||||
|
||||
fn version(&self) -> Result<DBVersion> {
|
||||
let results = self.meta_query("select * from meta where key='database_version'", &[])?;
|
||||
|
||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -13,7 +13,7 @@ use tiempo::commands::{
|
|||
Command, r#in::InCommand, display::DisplayCommand, sheet::SheetCommand,
|
||||
today::TodayCommand, yesterday::YesterdayCommand, week::WeekCommand,
|
||||
month::MonthCommand, list::ListCommand, out::OutCommand,
|
||||
resume::ResumeCommand, backend::BackendCommand,
|
||||
resume::ResumeCommand, backend::BackendCommand, kill::KillCommand,
|
||||
};
|
||||
|
||||
fn error_trap(matches: ArgMatches) -> error::Result<()> {
|
||||
|
@ -41,6 +41,7 @@ fn error_trap(matches: ArgMatches) -> error::Result<()> {
|
|||
|
||||
("sheet", Some(matches)) => SheetCommand::handle(matches.try_into()?, &mut conn, &mut out, &mut err, &config, now),
|
||||
("list", Some(matches)) => ListCommand::handle(matches.try_into()?, &mut conn, &mut out, &mut err, &config, now),
|
||||
("kill", Some(matches)) => KillCommand::handle(matches.try_into()?, &mut conn, &mut out, &mut err, &config, now),
|
||||
|
||||
(cmd, _) => Err(error::Error::UnimplementedCommand(cmd.into())),
|
||||
}
|
||||
|
@ -97,8 +98,7 @@ fn main() {
|
|||
Ok(())
|
||||
} else {
|
||||
Err(format!("the --id arg must be a number. '{}' is not a valid number", v))
|
||||
})
|
||||
.help("Use entry with ID instead of the last entry");
|
||||
});
|
||||
|
||||
// Now declar this app's cli
|
||||
let matches = App::new("Tiempo")
|
||||
|
@ -249,7 +249,7 @@ fn main() {
|
|||
.visible_alias("r")
|
||||
.about("Restart the timer for an entry. Defaults to the last active entry")
|
||||
.arg(at_arg.clone())
|
||||
.arg(id_arg.clone())
|
||||
.arg(id_arg.clone().help("Use entry with ID instead of the last entry"))
|
||||
)
|
||||
|
||||
.subcommand(SubCommand::with_name("out")
|
||||
|
@ -272,6 +272,19 @@ fn main() {
|
|||
.help("List archive sheets also"))
|
||||
)
|
||||
|
||||
.subcommand(SubCommand::with_name("kill")
|
||||
.visible_alias("k")
|
||||
.about("Delete an entry or an entire sheet")
|
||||
.arg(id_arg.clone().help("Delete entry with this ID instead of sheet"))
|
||||
.arg(Arg::with_name("sheet")
|
||||
.takes_value(true).value_name("SHEET")
|
||||
.conflicts_with("id")
|
||||
.required_unless("id")
|
||||
.help(
|
||||
"Delete an entire sheet by its name"
|
||||
))
|
||||
)
|
||||
|
||||
.get_matches();
|
||||
|
||||
if let Err(e) = error_trap(matches) {
|
||||
|
|
Loading…
Reference in New Issue