From 28cb90bbee2732ae72f50d28dbaa5e24718d9760 Mon Sep 17 00:00:00 2001 From: ZoOL Date: Sat, 30 Nov 2024 16:00:53 +0800 Subject: [PATCH] release 0.5 --- CHANGELOG.md | 4 +- Cargo.lock | 11 +++ Cargo.toml | 2 +- README.md | 26 ++++++- examples/cronjobs.rs | 8 +- src/lib.rs | 176 ++++++++++++++++++++++++++++--------------- 6 files changed, 156 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3219b07..df0ad4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ # Changelog -## [unreleased] +## [0.5.0] * bump `bevy_ecs` version to `0.15.0` * upgrade `cron` to `0.13.0` +* support english pattern for cronjob by [english-to-cron](https://github.com/kaplanelad/english-to-cron) +* system run time is now in Local time ## [0.5.0-rc.1] - 2024-10-23 diff --git a/Cargo.lock b/Cargo.lock index 5e5d8ee..4686ed0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,6 +138,7 @@ dependencies = [ "bevy_ecs", "chrono", "cron", + "english-to-cron", ] [[package]] @@ -634,6 +635,16 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "english-to-cron" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c16423ac933fee80f05a52b435a912d5b08edbbbfe936e0042ebb3accdf303da" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "equivalent" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 2cbb64b..1c54566 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ bevy_ecs = { version = "0.15.0" } cron = "0.13.0" chrono = "0.4.19" - +english-to-cron = "0.1.2" [dev-dependencies] bevy = { version = "0.15.0", default-features = false, features = [] } diff --git a/README.md b/README.md index 13fab15..7b32f32 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # bevy_cronjob -`bevy_cronjob` is a simple helper to run cronjobs (at repeated schedule) in Bevy. +`bevy_cronjob` is a simple helper to run cronjob (at repeated schedule) in Bevy. ## Usage @@ -26,9 +26,12 @@ fn main() { ))), ) .add_plugins(LogPlugin::default()) - .add_systems(Update, print_per_5_sec.run_if(schedule_passed("0/5 * * * * *"))) - .add_systems(Update, print_per_min.run_if(schedule_passed("0 * * * * *"))) - .add_systems(Update, print_per_hour.run_if(schedule_passed("0 0 * * * *"))) + .add_systems( + Update, + print_per_5_sec.run_if(schedule_passed("every 5 seconds")), + ) + .add_systems(Update, print_per_min.run_if(schedule_passed("every 1 minute"))) + .add_systems(Update, print_per_hour.run_if(schedule_passed("every hour"))) .run(); } @@ -61,6 +64,21 @@ every 15 seconds. Ranges can be specified with a dash. For example `1-5 * * * * *`' would execute on every second for the first 5 seconds of a minute. +## Full List of Supported English Patterns + +supported by [english-to-cron](https://github.com/kaplanelad/english-to-cron) + +| English Phrase | CronJob Syntax | +|--------------------------------------------------|------------------| +| every 15 seconds | 0/15 * * * * ? * | +| run every minute | 0 * * * * ? * | +| fire every day at 4:00 pm | 0 0 16 */1 * ? * | +| at 10:00 am | 0 0 10 * * ? * | +| run at midnight on the 1st and 15th of the month | 0 0 0 1,15 * ? * | +| On Sunday at 12:00 | 0 0 12 ? * SUN * | +| 7pm every Thursday | 0 0 19 ? * THU * | +| midnight on Tuesdays | 0 0 ? * TUE * | + ## Supported Versions | bevy | bevy_cronjob | diff --git a/examples/cronjobs.rs b/examples/cronjobs.rs index 98b584e..0584921 100644 --- a/examples/cronjobs.rs +++ b/examples/cronjobs.rs @@ -7,7 +7,7 @@ use bevy::{ }; use bevy_ecs::prelude::IntoSystemConfigs; -use bevy_cronjob::{schedule_passed, EVERY_HOUR, EVERY_MIN}; +use bevy_cronjob::{schedule_passed}; fn main() { App::new() @@ -19,10 +19,10 @@ fn main() { .add_plugins(LogPlugin::default()) .add_systems( Update, - print_per_5_sec.run_if(schedule_passed("0/5 * * * * *")), + print_per_5_sec.run_if(schedule_passed("every 5 seconds")), ) - .add_systems(Update, print_per_min.run_if(schedule_passed(EVERY_MIN))) - .add_systems(Update, print_per_hour.run_if(schedule_passed(EVERY_HOUR))) + .add_systems(Update, print_per_min.run_if(schedule_passed("every 1 minute"))) + .add_systems(Update, print_per_hour.run_if(schedule_passed("every hour"))) .run(); } diff --git a/src/lib.rs b/src/lib.rs index a48fe29..0da6c89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use bevy_ecs::prelude::Local; use chrono::DateTime; use cron::Schedule; +pub use english_to_cron::str_cron_syntax; /// bevy_cronjob is a simple helper to run cronjobs (at repeated schedule) in Bevy. /// # Usage @@ -24,9 +25,9 @@ use cron::Schedule; /// ))), /// ) /// .add_plugins(LogPlugin::default()) -/// .add_systems(Update, print_per_5_sec.run_if(schedule_passed("0/5 * * * * *"))) -/// .add_systems(Update, print_per_min.run_if(schedule_passed("0 * * * * *"))) -/// .add_systems(Update, print_per_hour.run_if(schedule_passed("0 0 * * * *"))) +/// .add_systems(Update, print_per_5_sec.run_if(schedule_passed("0/5 * * * ? *"))) +/// .add_systems(Update, print_per_min.run_if(schedule_passed("0 * * * ? *"))) +/// .add_systems(Update, print_per_hour.run_if(schedule_passed("0 0 * * ? *"))) /// .run(); /// } /// @@ -60,95 +61,95 @@ use cron::Schedule; /// for the first 5 seconds of a minute. /// run every 5 sec -pub const EVERY_5_SEC: &str = "0/5 * * * * * *"; +pub const EVERY_5_SEC: &str = "0/5 * * * * ? *"; /// run every 10 sec -pub const EVERY_10_SEC: &str = "0/10 * * * * * *"; +pub const EVERY_10_SEC: &str = "0/10 * * * * ? *"; /// run every 30 sec -pub const EVERY_30_SEC: &str = "0/30 * * * * * *"; +pub const EVERY_30_SEC: &str = "0/30 * * * * ? *"; /// run every minute -pub const EVERY_MIN: &str = "0 * * * * * *"; +pub const EVERY_MIN: &str = "0 * * * * ? *"; /// run every 5 minutes -pub const EVERY_5_MIN: &str = "0 */5 * * * * *"; +pub const EVERY_5_MIN: &str = "0 0/5 * * * ? *"; /// run every 10 minutes -pub const EVERY_10_MIN: &str = "0 */10 * * * * *"; +pub const EVERY_10_MIN: &str = "0 0/10 * * * ? *"; /// run every 30 minutes -pub const EVERY_30_MIN: &str = "0 */30 * * * * *"; +pub const EVERY_30_MIN: &str = "0 0/30 * * * ? *"; /// run every hour -pub const EVERY_HOUR: &str = "0 0 * * * * *"; +pub const EVERY_HOUR: &str = "0 0 * * * ? *"; /// run every day -pub const EVERY_DAY: &str = "0 0 0 * * * *"; +pub const EVERY_DAY: &str = "0 0 0 */1 * ? *"; -/// run every day at 1 am UTC -pub const EVERY_1_AM: &str = "0 0 1 * * * *"; +/// run every day at 1 am +pub const EVERY_1_AM: &str = "0 0 1 */1 * ? *"; -/// run every day at 2 am UTC -pub const EVERY_2_AM: &str = "0 0 2 * * * *"; +/// run every day at 2 am +pub const EVERY_2_AM: &str = "0 0 2 */1 * ? *"; -/// run every day at 3 am UTC -pub const EVERY_3_AM: &str = "0 0 3 * * * *"; +/// run every day at 3 am +pub const EVERY_3_AM: &str = "0 0 3 */1 * ? *"; -/// run every day at 4 am UTC -pub const EVERY_4_AM: &str = "0 0 4 * * * *"; +/// run every day at 4 am +pub const EVERY_4_AM: &str = "0 0 4 */1 * ? *"; -/// run every day at 5 am UTC -pub const EVERY_5_AM: &str = "0 0 5 * * * *"; +/// run every day at 5 am +pub const EVERY_5_AM: &str = "0 0 5 */1 * ? *"; -/// run every day at 6 am UTC -pub const EVERY_6_AM: &str = "0 0 6 * * * *"; +/// run every day at 6 am +pub const EVERY_6_AM: &str = "0 0 6 */1 * ? *"; -/// run every day at 7 am UTC -pub const EVERY_7_AM: &str = "0 0 7 * * * *"; +/// run every day at 7 am +pub const EVERY_7_AM: &str = "0 0 7 */1 * ? *"; -/// run every day at 8 am UTC -pub const EVERY_8_AM: &str = "0 0 8 * * * *"; +/// run every day at 8 am +pub const EVERY_8_AM: &str = "0 0 8 */1 * ? *"; -/// run every day at 9 am UTC -pub const EVERY_9_AM: &str = "0 0 9 * * * *"; +/// run every day at 9 am +pub const EVERY_9_AM: &str = "0 0 9 */1 * ? *"; -/// run every day at 10 am UTC -pub const EVERY_10_AM: &str = "0 0 10 * * * *"; +/// run every day at 10 am +pub const EVERY_10_AM: &str = "0 0 10 */1 * ? *"; -/// run every day at 11 am UTC -pub const EVERY_11_AM: &str = "0 0 11 * * * *"; +/// run every day at 11 am +pub const EVERY_11_AM: &str = "0 0 11 */1 * ? *"; -/// run every day at 12 pm UTC -pub const EVERY_12_PM: &str = "0 0 12 * * * *"; +/// run every day at 12 pm +pub const EVERY_12_PM: &str = "0 0 12 */1 * ? *"; -/// run every day at 1 pm UTC -pub const EVERY_1_PM: &str = "0 0 13 * * * *"; +/// run every day at 1 pm +pub const EVERY_1_PM: &str = "0 0 13 */1 * ? *"; -/// run every day at 2 pm UTC -pub const EVERY_2_PM: &str = "0 0 14 * * * *"; +/// run every day at 2 pm +pub const EVERY_2_PM: &str = "0 0 14 */1 * ? *"; -/// run every day at 3 pm UTC -pub const EVERY_3_PM: &str = "0 0 15 * * * *"; +/// run every day at 3 pm +pub const EVERY_3_PM: &str = "0 0 15 */1 * ? *"; -/// run every day at 4 pm UTC -pub const EVERY_4_PM: &str = "0 0 16 * * * *"; +/// run every day at 4 pm +pub const EVERY_4_PM: &str = "0 0 16 */1 * ? *"; -/// run every day at 5 pm UTC -pub const EVERY_5_PM: &str = "0 0 17 * * * *"; +/// run every day at 5 pm +pub const EVERY_5_PM: &str = "0 0 17 */1 * ? *"; -/// run every day at 6 pm UTC -pub const EVERY_6_PM: &str = "0 0 18 * * * *"; +/// run every day at 6 pm +pub const EVERY_6_PM: &str = "0 0 18 */1 * ? *"; -/// run every day at 7 pm UTC -pub const EVERY_7_PM: &str = "0 0 19 * * * *"; +/// run every day at 7 pm +pub const EVERY_7_PM: &str = "0 0 19 */1 * ? *"; -/// run every day at 8 pm UTC -pub const EVERY_8_PM: &str = "0 0 20 * * * *"; +/// run every day at 8 pm +pub const EVERY_8_PM: &str = "0 0 20 */1 * ? *"; -/// run every day at 9 pm UTC -pub const EVERY_9_PM: &str = "0 0 21 * * * *"; +/// run every day at 9 pm +pub const EVERY_9_PM: &str = "0 0 21 */1 * ? *"; -/// run every day at 10 pm UTC -pub const EVERY_10_PM: &str = "0 0 22 * * * *"; +/// run every day at 10 pm +pub const EVERY_10_PM: &str = "0 0 22 */1 * ? *"; -/// run every day at 11 pm UTC -pub const EVERY_11_PM: &str = "0 0 23 * * * *"; +/// run every day at 11 pm +pub const EVERY_11_PM: &str = "0 0 23 */1 * ? *"; -/// run every day at 12 am UTC -pub const EVERY_12_AM: &str = "0 0 0 * * * *"; +/// run every day at 12 am +pub const EVERY_12_AM: &str = "0 0 0 */1 * ? *"; /// Creates a closure that checks if the cron expression has passed /// # expression format: @@ -165,10 +166,26 @@ pub const EVERY_12_AM: &str = "0 0 0 * * * *"; /// |0 * * * * * | every minute | /// |0 5,10 * * * * | every hour on 5 and 10 min| /// |0 0 1 * * * | every day on 1:00:00| +/// +/// # english expression: +/// | expression | equal crontab expression| +/// |------|------| +/// |every 5 seconds | 0/5 * * * * *| +/// |every minute | 0 * * * * *| +/// |every hour | 0 0 * * * *| +/// |every day | 0 0 0 */1 * *| +/// |every day at 1 am | 0 0 1 */1 * *| +/// pub fn schedule_passed( expression: &str, ) -> impl FnMut(Local>>) -> bool { - let schedule = Schedule::from_str(expression).expect("Failed to parse cron expression"); + let new_expression = if expression.chars().any(|c| c.is_ascii_alphabetic()) { + str_cron_syntax(expression).expect("Failed to parse cron expression") + } else { + expression.to_string() + }; + + let schedule = Schedule::from_str(&new_expression).expect("Failed to parse cron expression"); move |mut local_schedule: Local>>| { if let Some(datetime) = schedule.upcoming(chrono::Local).next() { let now = chrono::Local::now(); @@ -187,3 +204,40 @@ pub fn schedule_passed( false } } + +#[test] +fn test_expression() { + assert_eq!(EVERY_5_SEC, str_cron_syntax("every 5 seconds").unwrap()); + assert_eq!(EVERY_10_SEC, str_cron_syntax("every 10 seconds").unwrap()); + assert_eq!(EVERY_30_SEC, str_cron_syntax("every 30 seconds").unwrap()); + assert_eq!(EVERY_MIN, str_cron_syntax("every minute").unwrap()); + assert_eq!(EVERY_5_MIN, str_cron_syntax("every 5 minutes").unwrap()); + assert_eq!(EVERY_10_MIN, str_cron_syntax("every 10 minutes").unwrap()); + assert_eq!(EVERY_30_MIN, str_cron_syntax("every 30 minutes").unwrap()); + assert_eq!(EVERY_HOUR, str_cron_syntax("every hour").unwrap()); + assert_eq!(EVERY_DAY, str_cron_syntax("every day").unwrap()); + assert_eq!(EVERY_1_AM, str_cron_syntax("every day at 1 am").unwrap()); + assert_eq!(EVERY_2_AM, str_cron_syntax("every day at 2 am").unwrap()); + assert_eq!(EVERY_3_AM, str_cron_syntax("every day at 3 am").unwrap()); + assert_eq!(EVERY_4_AM, str_cron_syntax("every day at 4 am").unwrap()); + assert_eq!(EVERY_5_AM, str_cron_syntax("every day at 5 am").unwrap()); + assert_eq!(EVERY_6_AM, str_cron_syntax("every day at 6 am").unwrap()); + assert_eq!(EVERY_7_AM, str_cron_syntax("every day at 7 am").unwrap()); + assert_eq!(EVERY_8_AM, str_cron_syntax("every day at 8 am").unwrap()); + assert_eq!(EVERY_9_AM, str_cron_syntax("every day at 9 am").unwrap()); + assert_eq!(EVERY_10_AM, str_cron_syntax("every day at 10 am").unwrap()); + assert_eq!(EVERY_11_AM, str_cron_syntax("every day at 11 am").unwrap()); + assert_eq!(EVERY_12_PM, str_cron_syntax("every day at 12 pm").unwrap()); + assert_eq!(EVERY_1_PM, str_cron_syntax("every day at 1 pm").unwrap()); + assert_eq!(EVERY_2_PM, str_cron_syntax("every day at 2 pm").unwrap()); + assert_eq!(EVERY_3_PM, str_cron_syntax("every day at 3 pm").unwrap()); + assert_eq!(EVERY_4_PM, str_cron_syntax("every day at 4 pm").unwrap()); + assert_eq!(EVERY_5_PM, str_cron_syntax("every day at 5 pm").unwrap()); + assert_eq!(EVERY_6_PM, str_cron_syntax("every day at 6 pm").unwrap()); + assert_eq!(EVERY_7_PM, str_cron_syntax("every day at 7 pm").unwrap()); + assert_eq!(EVERY_8_PM, str_cron_syntax("every day at 8 pm").unwrap()); + assert_eq!(EVERY_9_PM, str_cron_syntax("every day at 9 pm").unwrap()); + assert_eq!(EVERY_10_PM, str_cron_syntax("every day at 10 pm").unwrap()); + assert_eq!(EVERY_11_PM, str_cron_syntax("every day at 11 pm").unwrap()); + assert_eq!(EVERY_12_AM, str_cron_syntax("every day at 12 am").unwrap()); +}