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