commit c9f713390c35d056aa3b08d159f7bdd478139248 Author: Julio Biason Date: Sun May 3 20:51:24 2020 -0300 Add an event diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b94e3a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +events.toml +.idea +*.sw? diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4ceeb6c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,231 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "chrono" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +dependencies = [ + "num-integer", + "num-traits", + "time", +] + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "hermit-abi" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" + +[[package]] +name = "num-integer" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "serde" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" + +[[package]] +name = "serde_derive" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "syn" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +dependencies = [ + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +dependencies = [ + "serde", +] + +[[package]] +name = "tu" +version = "0.1.0" +dependencies = [ + "chrono", + "clap", + "serde", + "serde_derive", + "toml", +] + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..10479dd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "tu" +description = "TimeUP!" +version = "0.1.0" +authors = ["Julio Biason "] +edition = "2018" + +[dependencies] +chrono = "0.4.11" +clap = "2.33.0" +serde = "*" +serde_derive = "*" +toml = "0.5" diff --git a/src/args/mod.rs b/src/args/mod.rs new file mode 100644 index 0000000..46e8f63 --- /dev/null +++ b/src/args/mod.rs @@ -0,0 +1,75 @@ +use clap::crate_authors; +use clap::crate_description; +use clap::crate_name; +use clap::crate_version; +use clap::App; +use clap::Arg; +use clap::ArgMatches; +use clap::SubCommand; + +mod validators; + +type Description = String; +type Date = String; +type Time = String; + +#[derive(Debug)] +pub enum Action { + List, + Add(Description, Date), + AddWithTime(Description, Date, Time), +} + +pub fn parse() -> Result { + let params = App::new(crate_name!()) + .version(crate_version!()) + .author(crate_authors!()) + .about(crate_description!()) + .subcommand( + SubCommand::with_name("add") + .about("Add a new event") + .arg( + Arg::with_name("date") + .required(true) + .takes_value(true) + .validator(validators::date) + .help("Date for the event, in YYYY-MM-DD format"), + ) + .arg( + Arg::with_name("description") + .required(true) + .takes_value(true) + .help("Event description"), + ) + .arg( + Arg::with_name("time") + .short("t") + .long("time") + .takes_value(true) + .required(false) + .validator(validators::time) + .help("Time for the event"), + ), + ); + let matches = params.get_matches(); + + match matches.subcommand() { + ("", _) => Ok(Action::List), + ("add", Some(arguments)) => parse_add(arguments), + (_, _) => Err(()), + } +} + +fn parse_add(arguments: &ArgMatches) -> Result { + let description = arguments.value_of("description").unwrap(); + let date = arguments.value_of("date").unwrap(); + if let Some(time) = arguments.value_of("time") { + Ok(Action::AddWithTime( + description.into(), + date.into(), + time.into(), + )) + } else { + Ok(Action::Add(description.into(), date.into())) + } +} diff --git a/src/args/validators.rs b/src/args/validators.rs new file mode 100644 index 0000000..df94bbc --- /dev/null +++ b/src/args/validators.rs @@ -0,0 +1,19 @@ +use chrono::prelude::*; + +pub fn date(input: String) -> Result<(), String> { + let fake_datetime = format!("{} 00:00:00", input); + if let Ok(_) = dbg!(Utc.datetime_from_str(&fake_datetime, "%Y-%m-%d %H:%M:%S")) { + Ok(()) + } else { + Err(format!("Invalid date: '{}'", input)) + } +} + +pub fn time(input: String) -> Result<(), String> { + let fake_datetime = format!("2020-01-01 {}:00", input); + if let Ok(_) = dbg!(Utc.datetime_from_str(&fake_datetime, "%Y-%m-%d %H:%M:%S")) { + Ok(()) + } else { + Err(format!("Invalid time: '{}'", input)) + } +} diff --git a/src/eventlist/event.rs b/src/eventlist/event.rs new file mode 100644 index 0000000..0613acd --- /dev/null +++ b/src/eventlist/event.rs @@ -0,0 +1,47 @@ +use chrono::prelude::*; +use serde_derive::Deserialize; +use serde_derive::Serialize; + +#[derive(Serialize, Deserialize, Debug)] +pub struct Date { + year: i32, + month: u32, + day: u32, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Time { + hour: u32, + min: u32, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "due", content = "datetime")] +pub enum EventDateType { + AllDay(Date), + AtTime(Date, Time), +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Event { + description: String, + due: EventDateType, +} + +impl Event { + pub fn new_on_date(description: &str, date: &str) -> Self { + let fake_datetime = format!("{} 00:00:00", date); + if let Ok(dt) = Utc.datetime_from_str(&fake_datetime, "%Y-%m-%d %H:%M:%S") { + Self { + description: description.into(), + due: EventDateType::AllDay(Date { + year: dt.year(), + month: dt.month(), + day: dt.day(), + }), + } + } else { + panic!("Failed to parse the date"); + } + } +} diff --git a/src/eventlist/eventlist.rs b/src/eventlist/eventlist.rs new file mode 100644 index 0000000..4a69d8b --- /dev/null +++ b/src/eventlist/eventlist.rs @@ -0,0 +1,42 @@ +use serde_derive::Deserialize; +use serde_derive::Serialize; +use std::fs::File; +use std::io::{Read, Write}; +use toml; + +use crate::eventlist::event::Event; + +static FILENAME: &str = "events.toml"; + +#[derive(Serialize, Deserialize, Debug)] +pub struct EventList { + events: Vec, +} + +impl EventList { + fn empty() -> Self { + Self { events: Vec::new() } + } + + pub fn load() -> Self { + if let Ok(mut fp) = File::open(FILENAME) { + let mut content = String::new(); + fp.read_to_string(&mut content) + .expect("Your event file is corrupted"); + toml::from_str(&content).unwrap_or(EventList::empty()) + } else { + EventList::empty() + } + } + + pub fn push(&mut self, event: Event) { + self.events.push(event); + } + + pub fn save(&self) { + let content = toml::to_string(&self).unwrap(); + if let Ok(mut fp) = File::create(FILENAME) { + fp.write_all(content.as_bytes()).unwrap(); + } + } +} diff --git a/src/eventlist/mod.rs b/src/eventlist/mod.rs new file mode 100644 index 0000000..52256bd --- /dev/null +++ b/src/eventlist/mod.rs @@ -0,0 +1,2 @@ +pub mod event; +pub mod eventlist; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..87107ce --- /dev/null +++ b/src/main.rs @@ -0,0 +1,26 @@ +mod args; +mod eventlist; + +use crate::eventlist::event::Event; +use crate::eventlist::eventlist::EventList; + +fn main() { + if let Ok(command) = dbg!(args::parse()) { + match command { + args::Action::List => list(), + args::Action::Add(description, date) => add_with_date(&description, &date), + _ => println!("Unknown command"), + } + } +} + +fn list() { + unimplemented!() +} + +fn add_with_date(description: &str, date: &str) { + let event = Event::new_on_date(description, date); + let mut event_list = dbg!(EventList::load()); + event_list.push(event); + event_list.save(); +}