okcool
parent
3c132528e3
commit
039c4dad04
|
|
@ -188,6 +188,7 @@ dependencies = [
|
|||
"chrono",
|
||||
"croner",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
]
|
||||
|
||||
|
|
@ -237,18 +238,18 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.200"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
|
||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.200"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
|
||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
|
|
@ -9,4 +9,5 @@ edition = "2021"
|
|||
chrono = "0.4.38"
|
||||
croner = "2.0.4"
|
||||
regex = "1.10.4"
|
||||
serde = { version = "1.0.202", features = [ "serde_derive" ] }
|
||||
serde_yaml = "0.9.34"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use serde_yaml;
|
||||
use serde;
|
||||
use chrono::{DateTime, Local};
|
||||
use chrono::naive::NaiveDateTime;
|
||||
use regex::Regex;
|
||||
|
|
@ -8,22 +9,41 @@ fn main() {
|
|||
println!("{:?}", Task::new())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Task(serde_yaml::Mapping);
|
||||
//pub todo: String,
|
||||
//pub detail: Option<String>,
|
||||
//pub sub: Vec<Task>,
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Task(serde_yaml::Mapping);
|
||||
|
||||
impl Task {
|
||||
fn new() -> Task {
|
||||
pub fn new() -> Task {
|
||||
Task(serde_yaml::Mapping::new())
|
||||
}
|
||||
|
||||
fn is_due(&self) -> bool {
|
||||
self.is_due_now(TS::now())
|
||||
pub fn from_value(v: serde_yaml::Value) -> Task {
|
||||
let mut result = Task::new();
|
||||
match v.as_mapping() {
|
||||
Some(m) => { result.0 = m.clone(); },
|
||||
None => { result.set_value("is".to_string(), v); },
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
fn is_due_now(&self, now: TS) -> bool {
|
||||
pub fn from_reader(r: impl std::io::Read) -> Result<Vec<Task>, String> {
|
||||
let mut result = vec![];
|
||||
match serde_yaml::from_reader::<_, Vec<serde_yaml::Value>>(r) {
|
||||
Ok(v) => {
|
||||
result.extend(v.iter().map(|x| {
|
||||
Task::from_value(x.clone())
|
||||
}));
|
||||
Ok(result)
|
||||
},
|
||||
Err(msg) => Err(format!("failed to read: {}", msg)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_due(&self) -> bool {
|
||||
self.is_due_at(TS::now())
|
||||
}
|
||||
|
||||
fn is_due_at(&self, now: TS) -> bool {
|
||||
match self.when() {
|
||||
Some(when) => {
|
||||
now.unix() >= when.next(self.ts()).unix()
|
||||
|
|
@ -56,32 +76,53 @@ impl Task {
|
|||
}
|
||||
|
||||
fn get(&self, k: String) -> Option<String> {
|
||||
match self.get_value(k) {
|
||||
None => None,
|
||||
Some(v) => match v.as_str() {
|
||||
Some(s) => Some(s.to_string()),
|
||||
None => {assert!(false, "got not a string"); None },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_value(&self, k: String) -> Option<serde_yaml::Value> {
|
||||
match self.0.get(k) {
|
||||
Some(v) => Some(
|
||||
serde_yaml::to_string(v)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.trim()
|
||||
.trim_start_matches('\'')
|
||||
.trim_end_matches( '\'')
|
||||
.to_string()
|
||||
),
|
||||
Some(v) => Some(v.clone()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, k: String, v: String) {
|
||||
self.set_value(k, serde_yaml::Value::String(v));
|
||||
}
|
||||
|
||||
fn set_value(&mut self, k: String, v: serde_yaml::Value) {
|
||||
self.0.insert(
|
||||
serde_yaml::Value::String(k),
|
||||
serde_yaml::Value::String(v)
|
||||
v
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_task {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_reader_testdata() {
|
||||
let tasks = Task::from_reader(
|
||||
std::fs::File::open("./src/testdata/mvp.yaml").expect("failed to open file")
|
||||
).expect("failed to read file");
|
||||
eprintln!("tasks from_reader ./src/testdata/mvp.yaml: {:?}", tasks);
|
||||
assert_eq!(2, tasks.len());
|
||||
assert_eq!(1, tasks[0].0.len());
|
||||
assert!(tasks[0].get("is".to_string()).is_some());
|
||||
assert_eq!("x".to_string(), tasks[0].get("is".to_string()).unwrap());
|
||||
assert_eq!(1, tasks[1].0.len());
|
||||
assert_eq!("y and z".to_string(), tasks[1].get("is".to_string()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crud() {
|
||||
let mut t = Task::new();
|
||||
|
|
@ -100,9 +141,9 @@ mod test_task {
|
|||
let now = TS::new("2000-01-02T16:00Z".to_string()).unwrap();
|
||||
t.set("ts".to_string(), then.to_string());
|
||||
t.set("schedule".to_string(), "1h".to_string());
|
||||
assert!(!t.is_due_now(TS::from_unix(now.unix()-1)));
|
||||
assert!(t.is_due_now(TS::from_unix(now.unix())));
|
||||
assert!(t.is_due_now(TS::from_unix(now.unix()+1)));
|
||||
assert!(!t.is_due_at(TS::from_unix(now.unix()-1)));
|
||||
assert!(t.is_due_at(TS::from_unix(now.unix())));
|
||||
assert!(t.is_due_at(TS::from_unix(now.unix()+1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -113,9 +154,9 @@ mod test_task {
|
|||
let now = TS::new("2000-01-02T16:00Z".to_string()).unwrap();
|
||||
t.set("ts".to_string(), then.to_string());
|
||||
t.set("schedule".to_string(), "2000-01-02T16:00Z".to_string());
|
||||
assert!(!t.is_due_now(TS::from_unix(now.unix()-1)));
|
||||
assert!(t.is_due_now(TS::from_unix(now.unix())));
|
||||
assert!(t.is_due_now(TS::from_unix(now.unix()+1)));
|
||||
assert!(!t.is_due_at(TS::from_unix(now.unix()-1)));
|
||||
assert!(t.is_due_at(TS::from_unix(now.unix())));
|
||||
assert!(t.is_due_at(TS::from_unix(now.unix()+1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -126,9 +167,9 @@ mod test_task {
|
|||
let now = TS::new("2000-01-02T16:00Z".to_string()).unwrap();
|
||||
t.set("ts".to_string(), then.to_string());
|
||||
t.set("schedule".to_string(), "0 16 * * *".to_string());
|
||||
assert!(!t.is_due_now(TS::from_unix(now.unix()-1)));
|
||||
assert!(t.is_due_now(TS::from_unix(now.unix())));
|
||||
assert!(t.is_due_now(TS::from_unix(now.unix()+1)));
|
||||
assert!(!t.is_due_at(TS::from_unix(now.unix()-1)));
|
||||
assert!(t.is_due_at(TS::from_unix(now.unix())));
|
||||
assert!(t.is_due_at(TS::from_unix(now.unix()+1)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -275,7 +316,7 @@ mod test_cron {
|
|||
#[test]
|
||||
fn parse() {
|
||||
match Cron::new("* * * * *".to_string()) {
|
||||
Ok(c) => {}
|
||||
Ok(_) => {}
|
||||
Err(err) => assert!(false, "failed to parse cron: {}", err),
|
||||
};
|
||||
match Cron::new("1 * * * *".to_string()) {
|
||||
|
|
@ -375,7 +416,7 @@ impl TS {
|
|||
&format!("{}:00", src),
|
||||
"%Y-%m-%dT%H:%M",
|
||||
) {
|
||||
Ok(v) => { return Ok(TS(v.timestamp() as u64)) },
|
||||
Ok(v) => { return Ok(TS(v.and_utc().timestamp() as u64)) },
|
||||
_ => {},
|
||||
};
|
||||
Err(format!("cannot parse date format from {}", src))
|
||||
|
|
|
|||
Loading…
Reference in New Issue