implement old database handling for t edit

This commit is contained in:
Abraham Toriz 2021-08-04 18:27:08 -05:00
parent bbc691c79f
commit b767d9e476
No known key found for this signature in database
GPG Key ID: D5B4A746DB5DD42A
4 changed files with 86 additions and 27 deletions

View File

@ -136,12 +136,12 @@ mod tests {
#[test]
fn display_as_local_time_if_previous_version() {
std::env::set_var("TZ", "UTC");
let args = Default::default();
let mut db = SqliteDatabase::from_path("assets/test_old_db.db").unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
let config = Default::default();
std::env::set_var("TZ", "UTC");
DisplayCommand::handle(args, &mut db, &mut out, &mut err, &config, Utc::now()).unwrap();

View File

@ -9,8 +9,9 @@ use crate::error::{Error, Result};
use crate::commands::Command;
use crate::config::Config;
use crate::timeparse::parse_time;
use crate::old::{time_or_warning, warn_if_needed};
use crate::old::{entries_or_warning, time_or_warning, warn_if_needed};
use crate::formatters::text;
use crate::editor;
#[derive(Default)]
pub struct Args {
@ -22,6 +23,15 @@ pub struct Args {
note: Option<String>,
}
impl Args {
/// returns true only if no argument was passed other that possibly --id.
/// This means that an edit was requested without specifying what to edit,
/// therefore let's edit the note because why not
fn none_given(&self) -> bool {
!(self.start.is_some() || self.end.is_some() || self.r#move.is_some() || self.note.is_some())
}
}
impl<'a> TryFrom<&'a ArgMatches<'a>> for Args {
type Error = Error;
@ -67,28 +77,38 @@ impl<'a> Command<'a> for EditCommand {
return Ok(());
};
// normalize the entry in case it comes from an old database
let entry = entries_or_warning(vec![entry], db)?.0.into_iter().next().unwrap();
// try really hard to obtain the note
let note = if let Some(new_note) = args.note {
// either from the command's args
if args.append {
Some(entry.note.unwrap_or_else(|| "".to_owned()) + &config.append_notes_delimiter + &new_note)
} else {
Some(new_note)
}
} else if args.none_given() {
// or from the editor if no arguments where given
Some(editor::get_string(config.note_editor.as_deref(), entry.note)?)
} else {
// or just use watever was previously there is the user is editing
// something else
entry.note
};
db.entry_update(
entry.id,
args.start.unwrap_or(entry.start),
args.end.or(entry.end),
time_or_warning(args.start.unwrap_or(entry.start), db)?.0,
args.end.or(entry.end).map(|e| time_or_warning(e, db)).transpose()?.map(|o| o.0),
note,
&args.r#move.unwrap_or(entry.sheet),
)?;
let updated_entry = db.entry_by_id(entry.id)?.unwrap();
let updated_entry = entries_or_warning(vec![db.entry_by_id(entry.id)?.unwrap()], db)?.0;
text::print_formatted(
vec![updated_entry],
updated_entry,
out,
now,
true,
@ -104,6 +124,7 @@ impl<'a> Command<'a> for EditCommand {
mod tests {
use pretty_assertions::assert_eq;
use chrono::{Duration, TimeZone};
use ansi_term::Color::Yellow;
use crate::database::SqliteDatabase;
use crate::test_utils::Ps;
@ -112,6 +133,7 @@ mod tests {
#[test]
fn edit_last_note() {
std::env::set_var("TZ", "UTC");
let mut db = SqliteDatabase::from_memory().unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
@ -135,7 +157,7 @@ mod tests {
assert_eq!(Ps(&String::from_utf8_lossy(&out)), Ps("Timesheet: default
ID Day Start End Duration Notes
1 Tue Aug 03, 2021 14:29:00 - 15:29:00 1:00:00 new note
1 Tue Aug 03, 2021 19:29:00 - 20:29:00 1:00:00 new note
1:00:00
--------------------------------------------------------------
Total 1:00:00
@ -145,6 +167,8 @@ mod tests {
#[test]
fn edit_with_id() {
std::env::set_var("TZ", "UTC");
let mut db = SqliteDatabase::from_memory().unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
@ -165,7 +189,7 @@ mod tests {
assert_eq!(Ps(&String::from_utf8_lossy(&out)), Ps("Timesheet: sheet1
ID Day Start End Duration Notes
2 Tue Aug 03, 2021 14:29:00 - 15:29:00 1:00:00 new note
2 Tue Aug 03, 2021 19:29:00 - 20:29:00 1:00:00 new note
1:00:00
--------------------------------------------------------------
Total 1:00:00
@ -175,6 +199,7 @@ mod tests {
#[test]
fn edit_start() {
std::env::set_var("TZ", "UTC");
let mut db = SqliteDatabase::from_memory().unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
@ -193,7 +218,7 @@ mod tests {
assert_eq!(Ps(&String::from_utf8_lossy(&out)), Ps("Timesheet: default
ID Day Start End Duration Notes
1 Tue Aug 03, 2021 14:59:00 - 15:29:00 0:30:00 a note
1 Tue Aug 03, 2021 19:59:00 - 20:29:00 0:30:00 a note
0:30:00
------------------------------------------------------------
Total 0:30:00
@ -203,6 +228,7 @@ mod tests {
#[test]
fn edit_end() {
std::env::set_var("TZ", "UTC");
let mut db = SqliteDatabase::from_memory().unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
@ -221,7 +247,7 @@ mod tests {
assert_eq!(Ps(&String::from_utf8_lossy(&out)), Ps("Timesheet: default
ID Day Start End Duration Notes
1 Tue Aug 03, 2021 14:29:00 - 14:59:00 0:30:00 a note
1 Tue Aug 03, 2021 19:29:00 - 19:59:00 0:30:00 a note
0:30:00
------------------------------------------------------------
Total 0:30:00
@ -231,6 +257,7 @@ mod tests {
#[test]
fn edit_append() {
std::env::set_var("TZ", "UTC");
let mut db = SqliteDatabase::from_memory().unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
@ -250,7 +277,7 @@ mod tests {
assert_eq!(Ps(&String::from_utf8_lossy(&out)), Ps("Timesheet: default
ID Day Start End Duration Notes
1 Tue Aug 03, 2021 14:29:00 - 15:29:00 1:00:00 a note new note
1 Tue Aug 03, 2021 19:29:00 - 20:29:00 1:00:00 a note new note
1:00:00
---------------------------------------------------------------------
Total 1:00:00
@ -260,6 +287,7 @@ mod tests {
#[test]
fn edit_move() {
std::env::set_var("TZ", "UTC");
let mut db = SqliteDatabase::from_memory().unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
@ -278,7 +306,7 @@ mod tests {
assert_eq!(Ps(&String::from_utf8_lossy(&out)), Ps("Timesheet: new sheet
ID Day Start End Duration Notes
1 Tue Aug 03, 2021 14:29:00 - 15:29:00 1:00:00 a note
1 Tue Aug 03, 2021 19:29:00 - 20:29:00 1:00:00 a note
1:00:00
------------------------------------------------------------
Total 1:00:00
@ -286,13 +314,10 @@ mod tests {
assert_eq!(Ps(&String::from_utf8_lossy(&err)), Ps(""));
}
#[test]
fn warn_old() {
assert!(false);
}
#[test]
fn non_default_delimiter() {
std::env::set_var("TZ", "UTC");
let mut db = SqliteDatabase::from_memory().unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
@ -316,7 +341,7 @@ mod tests {
assert_eq!(Ps(&String::from_utf8_lossy(&out)), Ps("Timesheet: default
ID Day Start End Duration Notes
1 Tue Aug 03, 2021 14:29:00 - 15:29:00 1:00:00 a note;new note
1 Tue Aug 03, 2021 19:29:00 - 20:29:00 1:00:00 a note;new note
1:00:00
---------------------------------------------------------------------
Total 1:00:00
@ -325,7 +350,31 @@ mod tests {
}
#[test]
fn without_arguments_call_editor() {
assert!(false);
fn warn_old() {
std::env::set_var("TZ", "UTC");
let mut db = SqliteDatabase::from_path("assets/test_old_db.db").unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
let now = Utc.ymd(2021, 8, 3).and_hms(20, 29, 0);
let new_end = Utc.ymd(2021, 06, 29).and_hms(8, 26, 52);
let args = Args {
end: Some(new_end),
..Default::default()
};
EditCommand::handle(args, &mut db, &mut out, &mut err, &Default::default(), now).unwrap();
assert_eq!(Ps(&String::from_utf8_lossy(&out)), Ps("Timesheet: default
ID Day Start End Duration Notes
1 Tue Jun 29, 2021 06:26:49 - 08:26:52 2:00:02 lets do some rust
2:00:02
-----------------------------------------------------------------------
Total 2:00:02
"));
assert_eq!(
String::from_utf8_lossy(&err),
format!("{} You are using the old timetrap format, it is advised that you update your database using t migrate\n", Yellow.bold().paint("[WARNING]")),
);
}
}

View File

@ -50,16 +50,16 @@ impl<'a> Command<'a> for InCommand {
}
let note = if let Some(note) = args.note {
Some(note)
Some(note.trim().to_owned())
} else if !config.require_note {
None
} else {
Some(editor::get_string(config.note_editor.clone())?)
Some(editor::get_string(config.note_editor.as_deref(), None)?)
};
let (start, needs_warning) = time_or_warning(start, db)?;
db.entry_insert(start, None, note.map(|n| n.trim().to_owned()), &sheet)?;
db.entry_insert(start, None, note.map(|n| n), &sheet)?;
writeln!(out, "Checked into sheet \"{}\".", sheet)?;

View File

@ -1,13 +1,18 @@
use std::process::{Command, Stdio};
use std::io::Read;
use std::io::{Read, Write, Seek, SeekFrom};
use tempfile::NamedTempFile;
use crate::error::{Error::*, Result};
pub fn get_string(note_editor: Option<String>) -> Result<String> {
/// Launches the specified editor editing a temporary file and returns the
/// contents written by the user.
///
/// If prev_contents is Some(s) then the temporary file is started with those
/// contents.
pub fn get_string(note_editor: Option<&str>, prev_contents: Option<String>) -> Result<String> {
let note_editor = if let Some(note_editor) = note_editor {
note_editor
note_editor.to_owned()
} else if let Ok(editor_env) = std::env::var("EDITOR") {
editor_env
} else {
@ -31,6 +36,11 @@ pub fn get_string(note_editor: Option<String>) -> Result<String> {
let mut tmpfile = NamedTempFile::new().map_err(|e| NoTmpFile(e.to_string()))?;
if let Some(contents) = prev_contents {
tmpfile.write(contents.as_bytes())?;
tmpfile.seek(SeekFrom::Start(0))?;
}
c.arg(tmpfile.as_ref());
let status = c
@ -48,7 +58,7 @@ pub fn get_string(note_editor: Option<String>) -> Result<String> {
tmpfile.read_to_string(&mut note).map_err(|e| CouldntReadTmpFile(e.to_string()))?;
Ok(note)
Ok(note.trim().to_owned())
} else {
Err(EditorFailed { editor: note_editor.clone(), error: status.to_string() })
}