* [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time
@ 2021-11-30 12:11 Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 01/14] proxmox-time: calendar-events: implement repeated ranges Dominik Csapak
` (15 more replies)
0 siblings, 16 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:11 UTC (permalink / raw)
To: pbs-devel
adds two new features to calendar events (1/14 and 2/14):
* repeated range syntax: '7..17/2' means '7,9,11,13,15,17' (much shorter)
* make hours optional (all hours are selected then), necessary for pve
compatibility
patches 3-14/14 are cleanup, code moves and rustfmt commits, so that
the code is better organized (and more idiomatic rust, e.g.
impl FromStr instead of 'parse_*')
these should be backwards compatible, so no major version bump necessary
proxmox-backup patch is to not use the deprecated functions anymore
proxmox:
Dominik Csapak (14):
proxmox-time: calendar-events: implement repeated ranges
proxmox-time: calendar-events: make hour optional
proxmox-time: move common parse functions to parse_helpers
proxmox-time: move WeekDays into own file
proxmox-time: split DateTimeValue into own file
proxmox-time: move parse_daily_duration to daily_duration.rs
proxmox-time: daily_duration.rs: rustfmt
proxmox-time: move CalendarEvent into calendar_events.rs
proxmox-time: move TimeSpan into time_span.rs
proxmox-time: move tests from time.rs to test.rs
proxmox-time: lib.rs: rustfmt
proxmox-time: calendar-events: make compute_next_event a method
proxmox-time: calendar_events: implement FromStr
proxmox-time: time-span: implement FromStr
proxmox-time/src/calendar_event.rs | 447 +++++++++++++++++++++
proxmox-time/src/daily_duration.rs | 130 ++++--
proxmox-time/src/date_time_value.rs | 82 ++++
proxmox-time/src/lib.rs | 38 +-
proxmox-time/src/parse_helpers.rs | 75 ++++
proxmox-time/src/parse_time.rs | 513 ------------------------
proxmox-time/src/test.rs | 263 +++++++++++++
proxmox-time/src/time.rs | 591 ----------------------------
proxmox-time/src/time_span.rs | 274 +++++++++++++
proxmox-time/src/week_days.rs | 69 ++++
10 files changed, 1332 insertions(+), 1150 deletions(-)
create mode 100644 proxmox-time/src/calendar_event.rs
create mode 100644 proxmox-time/src/date_time_value.rs
create mode 100644 proxmox-time/src/parse_helpers.rs
delete mode 100644 proxmox-time/src/parse_time.rs
create mode 100644 proxmox-time/src/test.rs
delete mode 100644 proxmox-time/src/time.rs
create mode 100644 proxmox-time/src/time_span.rs
create mode 100644 proxmox-time/src/week_days.rs
proxmox-backup:
Dominik Csapak (1):
remove use of deprecated functions from proxmox-time
pbs-api-types/src/tape/media_pool.rs | 6 +++---
src/bin/proxmox-backup-proxy.rs | 10 +++++-----
src/server/jobstate.rs | 6 +++---
src/tape/inventory.rs | 3 +--
src/tape/media_pool.rs | 3 +--
src/tape/test/compute_media_state.rs | 4 ++--
6 files changed, 15 insertions(+), 17 deletions(-)
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 01/14] proxmox-time: calendar-events: implement repeated ranges
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
@ 2021-11-30 12:11 ` Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 02/14] proxmox-time: calendar-events: make hour optional Dominik Csapak
` (14 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:11 UTC (permalink / raw)
To: pbs-devel
so that we can have e.g. '7..17/2:00' as timespec
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/parse_time.rs | 10 +++++++---
proxmox-time/src/time.rs | 27 ++++++++++++++++++++++-----
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs
index 89d147e..8159a1a 100644
--- a/proxmox-time/src/parse_time.rs
+++ b/proxmox-time/src/parse_time.rs
@@ -191,12 +191,16 @@ fn parse_date_time_comp(max: usize) -> impl Fn(&str) -> IResult<&str, DateTimeVa
if value > end {
return Err(parse_error(i, "range start is bigger than end"));
}
- return Ok((i, DateTimeValue::Range(value, end)))
+ if let Some(time) = i.strip_prefix('/') {
+ let (time, repeat) = parse_time_comp(max)(time)?;
+ return Ok((time, DateTimeValue::Repeated(value, repeat, Some(end))));
+ }
+ return Ok((i, DateTimeValue::Range(value, end)));
}
if let Some(time) = i.strip_prefix('/') {
let (time, repeat) = parse_time_comp(max)(time)?;
- Ok((time, DateTimeValue::Repeated(value, repeat)))
+ Ok((time, DateTimeValue::Repeated(value, repeat, None)))
} else {
Ok((i, DateTimeValue::Single(value)))
}
@@ -209,7 +213,7 @@ fn parse_date_time_comp_list(start: u32, max: usize) -> impl Fn(&str) -> IResult
if let Some(time) = rest.strip_prefix('/') {
let (n, repeat) = parse_time_comp(max)(time)?;
if repeat > 0 {
- return Ok((n, vec![DateTimeValue::Repeated(start, repeat)]));
+ return Ok((n, vec![DateTimeValue::Repeated(start, repeat, None)]));
}
}
return Ok((rest, Vec::new()));
diff --git a/proxmox-time/src/time.rs b/proxmox-time/src/time.rs
index a220f2c..2dfe425 100644
--- a/proxmox-time/src/time.rs
+++ b/proxmox-time/src/time.rs
@@ -25,7 +25,7 @@ bitflags!{
pub(crate) enum DateTimeValue {
Single(u32),
Range(u32, u32),
- Repeated(u32, u32),
+ Repeated(u32, u32, Option<u32>),
}
impl DateTimeValue {
@@ -34,11 +34,16 @@ impl DateTimeValue {
match self {
DateTimeValue::Single(v) => *v == value,
DateTimeValue::Range(start, end) => value >= *start && value <= *end,
- DateTimeValue::Repeated(start, repetition) => {
+ DateTimeValue::Repeated(start, repetition, opt_end) => {
if value >= *start {
if *repetition > 0 {
let offset = value - start;
- offset % repetition == 0
+ let res = offset % repetition == 0;
+ if let Some(end) = opt_end {
+ res && value <= *end
+ } else {
+ res
+ }
} else {
*start == value
}
@@ -78,11 +83,18 @@ impl DateTimeValue {
}
}
}
- DateTimeValue::Repeated(start, repetition) => {
+ DateTimeValue::Repeated(start, repetition, opt_end) => {
if value < *start {
set_next(*start);
} else if *repetition > 0 {
- set_next(start + ((value - start + repetition) / repetition) * repetition);
+ let n = start + ((value - start + repetition) / repetition) * repetition;
+ if let Some(end) = opt_end {
+ if n <= *end {
+ set_next(n);
+ }
+ } else {
+ set_next(n);
+ }
}
}
}
@@ -455,6 +467,11 @@ mod test {
test_value("sat", THURSDAY_00_00, THURSDAY_00_00 + 2*DAY)?;
test_value("sun", THURSDAY_00_00, THURSDAY_00_00 + 3*DAY)?;
+ // test repeated ranges
+ test_value("4..10/2:0", THURSDAY_00_00, THURSDAY_00_00 + 4*HOUR)?;
+ test_value("4..10/2:0", THURSDAY_00_00 + 5*HOUR, THURSDAY_00_00 + 6*HOUR)?;
+ test_value("4..10/2:0", THURSDAY_00_00 + 11*HOUR, THURSDAY_00_00 + 1*DAY + 4*HOUR)?;
+
// test multiple values for a single field
// and test that the order does not matter
test_value("5,10:4,8", THURSDAY_00_00, THURSDAY_00_00 + 5*HOUR + 4*MIN)?;
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 02/14] proxmox-time: calendar-events: make hour optional
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 01/14] proxmox-time: calendar-events: implement repeated ranges Dominik Csapak
@ 2021-11-30 12:11 ` Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 03/14] proxmox-time: move common parse functions to parse_helpers Dominik Csapak
` (13 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:11 UTC (permalink / raw)
To: pbs-devel
to be compatible with our perl calendar events, we have to make hour optional
in that case we select every hour, so 'X' is the same as writing '*:X'
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/parse_time.rs | 17 ++++++++---------
proxmox-time/src/time.rs | 4 ++++
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs
index 8159a1a..aa1c58e 100644
--- a/proxmox-time/src/parse_time.rs
+++ b/proxmox-time/src/parse_time.rs
@@ -10,7 +10,7 @@ use nom::{
error::{context, ParseError, VerboseError},
bytes::complete::{tag, take_while1},
combinator::{map_res, all_consuming, opt, recognize},
- sequence::{pair, preceded, tuple},
+ sequence::{pair, preceded, terminated, tuple},
character::complete::{alpha1, space0, digit1},
multi::separated_nonempty_list,
};
@@ -225,17 +225,16 @@ fn parse_date_time_comp_list(start: u32, max: usize) -> impl Fn(&str) -> IResult
fn parse_time_spec(i: &str) -> IResult<&str, TimeSpec> {
- let (i, (hour, minute, opt_second)) = tuple((
- parse_date_time_comp_list(0, 24),
- preceded(tag(":"), parse_date_time_comp_list(0, 60)),
+ let (i, (opt_hour, minute, opt_second)) = tuple((
+ opt(terminated(parse_date_time_comp_list(0, 24), tag(":"))),
+ parse_date_time_comp_list(0, 60),
opt(preceded(tag(":"), parse_date_time_comp_list(0, 60))),
))(i)?;
- if let Some(second) = opt_second {
- Ok((i, TimeSpec { hour, minute, second }))
- } else {
- Ok((i, TimeSpec { hour, minute, second: vec![DateTimeValue::Single(0)] }))
- }
+ let hour = opt_hour.unwrap_or_else(Vec::new);
+ let second = opt_second.unwrap_or_else(|| vec![DateTimeValue::Single(0)]);
+
+ Ok((i, TimeSpec { hour, minute, second }))
}
fn parse_date_spec(i: &str) -> IResult<&str, DateSpec> {
diff --git a/proxmox-time/src/time.rs b/proxmox-time/src/time.rs
index 2dfe425..fb18949 100644
--- a/proxmox-time/src/time.rs
+++ b/proxmox-time/src/time.rs
@@ -451,6 +451,10 @@ mod test {
const JUL_31_2020: i64 = 1596153600; // Friday, 2020-07-31 00:00:00
const DEC_31_2020: i64 = 1609372800; // Thursday, 2020-12-31 00:00:00
+ // minute only syntax
+ test_value("0", THURSDAY_00_00, THURSDAY_00_00 + HOUR)?;
+ test_value("*", THURSDAY_00_00, THURSDAY_00_00 + MIN)?;
+
test_value("*:0", THURSDAY_00_00, THURSDAY_00_00 + HOUR)?;
test_value("*:*", THURSDAY_00_00, THURSDAY_00_00 + MIN)?;
test_value("*:*:*", THURSDAY_00_00, THURSDAY_00_00 + 1)?;
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 03/14] proxmox-time: move common parse functions to parse_helpers
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 01/14] proxmox-time: calendar-events: implement repeated ranges Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 02/14] proxmox-time: calendar-events: make hour optional Dominik Csapak
@ 2021-11-30 12:11 ` Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 04/14] proxmox-time: move WeekDays into own file Dominik Csapak
` (12 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:11 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/lib.rs | 2 +
proxmox-time/src/parse_helpers.rs | 75 +++++++++++++++++++++++++++++++
proxmox-time/src/parse_time.rs | 56 +----------------------
3 files changed, 78 insertions(+), 55 deletions(-)
create mode 100644 proxmox-time/src/parse_helpers.rs
diff --git a/proxmox-time/src/lib.rs b/proxmox-time/src/lib.rs
index d72509f..d2a4cb7 100644
--- a/proxmox-time/src/lib.rs
+++ b/proxmox-time/src/lib.rs
@@ -13,6 +13,8 @@ pub use parse_time::*;
mod time;
pub use time::*;
+pub(crate) mod parse_helpers;
+
mod daily_duration;
pub use daily_duration::*;
diff --git a/proxmox-time/src/parse_helpers.rs b/proxmox-time/src/parse_helpers.rs
new file mode 100644
index 0000000..4890b2f
--- /dev/null
+++ b/proxmox-time/src/parse_helpers.rs
@@ -0,0 +1,75 @@
+use anyhow::{bail, Error};
+
+use super::daily_duration::*;
+
+use nom::{
+ bytes::complete::tag,
+ character::complete::digit1,
+ combinator::{all_consuming, map_res, opt, recognize},
+ error::{ParseError, VerboseError},
+ sequence::{preceded, tuple},
+};
+
+pub(crate) type IResult<I, O, E = VerboseError<I>> = Result<(I, O), nom::Err<E>>;
+
+pub(crate) fn parse_error<'a>(
+ i: &'a str,
+ context: &'static str,
+) -> nom::Err<VerboseError<&'a str>> {
+ let err = VerboseError { errors: Vec::new() };
+ let err = VerboseError::add_context(i, context, err);
+ nom::Err::Error(err)
+}
+
+// Parse a 64 bit unsigned integer
+pub(crate) fn parse_u64(i: &str) -> IResult<&str, u64> {
+ map_res(recognize(digit1), str::parse)(i)
+}
+
+// Parse complete input, generate simple error message (use this for sinple line input).
+pub(crate) fn parse_complete_line<'a, F, O>(what: &str, i: &'a str, parser: F) -> Result<O, Error>
+where
+ F: Fn(&'a str) -> IResult<&'a str, O>,
+{
+ match all_consuming(parser)(i) {
+ Err(nom::Err::Error(VerboseError { errors }))
+ | Err(nom::Err::Failure(VerboseError { errors })) => {
+ if errors.is_empty() {
+ bail!("unable to parse {}", what);
+ } else {
+ bail!(
+ "unable to parse {} at '{}' - {:?}",
+ what,
+ errors[0].0,
+ errors[0].1
+ );
+ }
+ }
+ Err(err) => {
+ bail!("unable to parse {} - {}", what, err);
+ }
+ Ok((_, data)) => Ok(data),
+ }
+}
+
+pub(crate) fn parse_time_comp(max: usize) -> impl Fn(&str) -> IResult<&str, u32> {
+ move |i: &str| {
+ let (i, v) = map_res(recognize(digit1), str::parse)(i)?;
+ if (v as usize) >= max {
+ return Err(parse_error(i, "time value too large"));
+ }
+ Ok((i, v))
+ }
+}
+
+pub(crate) fn parse_hm_time(i: &str) -> IResult<&str, HmTime> {
+ let (i, (hour, opt_minute)) = tuple((
+ parse_time_comp(24),
+ opt(preceded(tag(":"), parse_time_comp(60))),
+ ))(i)?;
+
+ match opt_minute {
+ Some(minute) => Ok((i, HmTime { hour, minute })),
+ None => Ok((i, HmTime { hour, minute: 0 })),
+ }
+}
diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs
index aa1c58e..7b0e168 100644
--- a/proxmox-time/src/parse_time.rs
+++ b/proxmox-time/src/parse_time.rs
@@ -15,38 +15,7 @@ use nom::{
multi::separated_nonempty_list,
};
-type IResult<I, O, E = VerboseError<I>> = Result<(I, O), nom::Err<E>>;
-
-fn parse_error<'a>(i: &'a str, context: &'static str) -> nom::Err<VerboseError<&'a str>> {
- let err = VerboseError { errors: Vec::new() };
- let err = VerboseError::add_context(i, context, err);
- nom::Err::Error(err)
-}
-
-// Parse a 64 bit unsigned integer
-fn parse_u64(i: &str) -> IResult<&str, u64> {
- map_res(recognize(digit1), str::parse)(i)
-}
-
-// Parse complete input, generate simple error message (use this for sinple line input).
-fn parse_complete_line<'a, F, O>(what: &str, i: &'a str, parser: F) -> Result<O, Error>
- where F: Fn(&'a str) -> IResult<&'a str, O>,
-{
- match all_consuming(parser)(i) {
- Err(nom::Err::Error(VerboseError { errors })) |
- Err(nom::Err::Failure(VerboseError { errors })) => {
- if errors.is_empty() {
- bail!("unable to parse {}", what);
- } else {
- bail!("unable to parse {} at '{}' - {:?}", what, errors[0].0, errors[0].1);
- }
- }
- Err(err) => {
- bail!("unable to parse {} - {}", what, err);
- }
- Ok((_, data)) => Ok(data),
- }
-}
+use crate::parse_helpers::{parse_complete_line, parse_error, parse_hm_time, parse_time_comp, parse_u64, IResult};
lazy_static! {
static ref TIME_SPAN_UNITS: HashMap<&'static str, f64> = {
@@ -129,16 +98,6 @@ struct DateSpec {
day: Vec<DateTimeValue>,
}
-fn parse_time_comp(max: usize) -> impl Fn(&str) -> IResult<&str, u32> {
- move |i: &str| {
- let (i, v) = map_res(recognize(digit1), str::parse)(i)?;
- if (v as usize) >= max {
- return Err(parse_error(i, "time value too large"));
- }
- Ok((i, v))
- }
-}
-
fn parse_weekday(i: &str) -> IResult<&str, WeekDays> {
let (i, text) = alpha1(i)?;
@@ -501,16 +460,3 @@ fn parse_daily_duration_incomplete(mut i: &str) -> IResult<&str, DailyDuration>
Ok((i, duration))
}
-
-fn parse_hm_time(i: &str) -> IResult<&str, HmTime> {
-
- let (i, (hour, opt_minute)) = tuple((
- parse_time_comp(24),
- opt(preceded(tag(":"), parse_time_comp(60))),
- ))(i)?;
-
- match opt_minute {
- Some(minute) => Ok((i, HmTime { hour, minute })),
- None => Ok((i, HmTime { hour, minute: 0})),
- }
-}
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 04/14] proxmox-time: move WeekDays into own file
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (2 preceding siblings ...)
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 03/14] proxmox-time: move common parse functions to parse_helpers Dominik Csapak
@ 2021-11-30 12:11 ` Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 05/14] proxmox-time: split DateTimeValue " Dominik Csapak
` (11 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:11 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/lib.rs | 3 ++
proxmox-time/src/parse_time.rs | 45 +---------------------
proxmox-time/src/time.rs | 16 +-------
proxmox-time/src/week_days.rs | 69 ++++++++++++++++++++++++++++++++++
4 files changed, 74 insertions(+), 59 deletions(-)
create mode 100644 proxmox-time/src/week_days.rs
diff --git a/proxmox-time/src/lib.rs b/proxmox-time/src/lib.rs
index d2a4cb7..bce4b56 100644
--- a/proxmox-time/src/lib.rs
+++ b/proxmox-time/src/lib.rs
@@ -15,6 +15,9 @@ pub use time::*;
pub(crate) mod parse_helpers;
+mod week_days;
+pub use week_days::*;
+
mod daily_duration;
pub use daily_duration::*;
diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs
index 7b0e168..6dde4ae 100644
--- a/proxmox-time/src/parse_time.rs
+++ b/proxmox-time/src/parse_time.rs
@@ -16,6 +16,7 @@ use nom::{
};
use crate::parse_helpers::{parse_complete_line, parse_error, parse_hm_time, parse_time_comp, parse_u64, IResult};
+use crate::{parse_weekdays_range, WeekDays};
lazy_static! {
static ref TIME_SPAN_UNITS: HashMap<&'static str, f64> = {
@@ -98,50 +99,6 @@ struct DateSpec {
day: Vec<DateTimeValue>,
}
-fn parse_weekday(i: &str) -> IResult<&str, WeekDays> {
- let (i, text) = alpha1(i)?;
-
- match text.to_ascii_lowercase().as_str() {
- "monday" | "mon" => Ok((i, WeekDays::MONDAY)),
- "tuesday" | "tue" => Ok((i, WeekDays::TUESDAY)),
- "wednesday" | "wed" => Ok((i, WeekDays::WEDNESDAY)),
- "thursday" | "thu" => Ok((i, WeekDays::THURSDAY)),
- "friday" | "fri" => Ok((i, WeekDays::FRIDAY)),
- "saturday" | "sat" => Ok((i, WeekDays::SATURDAY)),
- "sunday" | "sun" => Ok((i, WeekDays::SUNDAY)),
- _ => return Err(parse_error(text, "weekday")),
- }
-}
-
-fn parse_weekdays_range(i: &str) -> IResult<&str, WeekDays> {
- let (i, startday) = parse_weekday(i)?;
-
- let generate_range = |start, end| {
- let mut res = 0;
- let mut pos = start;
- loop {
- res |= pos;
- if pos >= end { break; }
- pos <<= 1;
- }
- WeekDays::from_bits(res).unwrap()
- };
-
- if let (i, Some((_, endday))) = opt(pair(tag(".."),parse_weekday))(i)? {
- let start = startday.bits();
- let end = endday.bits();
- if start > end {
- let set1 = generate_range(start, WeekDays::SUNDAY.bits());
- let set2 = generate_range(WeekDays::MONDAY.bits(), end);
- Ok((i, set1 | set2))
- } else {
- Ok((i, generate_range(start, end)))
- }
- } else {
- Ok((i, startday))
- }
-}
-
fn parse_date_time_comp(max: usize) -> impl Fn(&str) -> IResult<&str, DateTimeValue> {
move |i: &str| {
let (i, value) = parse_time_comp(max)(i)?;
diff --git a/proxmox-time/src/time.rs b/proxmox-time/src/time.rs
index fb18949..2b2a936 100644
--- a/proxmox-time/src/time.rs
+++ b/proxmox-time/src/time.rs
@@ -1,26 +1,12 @@
use std::convert::TryInto;
use anyhow::Error;
-use bitflags::bitflags;
use crate::TmEditor;
+use crate::WeekDays;
use crate::{parse_calendar_event, parse_time_span};
-bitflags!{
- /// Defines one or more days of a week.
- #[derive(Default)]
- pub struct WeekDays: u8 {
- const MONDAY = 1;
- const TUESDAY = 2;
- const WEDNESDAY = 4;
- const THURSDAY = 8;
- const FRIDAY = 16;
- const SATURDAY = 32;
- const SUNDAY = 64;
- }
-}
-
#[derive(Debug, Clone)]
pub(crate) enum DateTimeValue {
Single(u32),
diff --git a/proxmox-time/src/week_days.rs b/proxmox-time/src/week_days.rs
new file mode 100644
index 0000000..64d4137
--- /dev/null
+++ b/proxmox-time/src/week_days.rs
@@ -0,0 +1,69 @@
+use bitflags::bitflags;
+use nom::{
+ bytes::complete::tag,
+ character::complete::alpha1,
+ combinator::opt,
+ sequence::pair,
+};
+
+use crate::parse_helpers::{parse_error, IResult};
+
+bitflags! {
+ /// Defines one or more days of a week.
+ #[derive(Default)]
+ pub struct WeekDays: u8 {
+ const MONDAY = 1;
+ const TUESDAY = 2;
+ const WEDNESDAY = 4;
+ const THURSDAY = 8;
+ const FRIDAY = 16;
+ const SATURDAY = 32;
+ const SUNDAY = 64;
+ }
+}
+
+fn parse_weekday(i: &str) -> IResult<&str, WeekDays> {
+ let (i, text) = alpha1(i)?;
+
+ match text.to_ascii_lowercase().as_str() {
+ "monday" | "mon" => Ok((i, WeekDays::MONDAY)),
+ "tuesday" | "tue" => Ok((i, WeekDays::TUESDAY)),
+ "wednesday" | "wed" => Ok((i, WeekDays::WEDNESDAY)),
+ "thursday" | "thu" => Ok((i, WeekDays::THURSDAY)),
+ "friday" | "fri" => Ok((i, WeekDays::FRIDAY)),
+ "saturday" | "sat" => Ok((i, WeekDays::SATURDAY)),
+ "sunday" | "sun" => Ok((i, WeekDays::SUNDAY)),
+ _ => return Err(parse_error(text, "weekday")),
+ }
+}
+
+pub(crate) fn parse_weekdays_range(i: &str) -> IResult<&str, WeekDays> {
+ let (i, startday) = parse_weekday(i)?;
+
+ let generate_range = |start, end| {
+ let mut res = 0;
+ let mut pos = start;
+ loop {
+ res |= pos;
+ if pos >= end {
+ break;
+ }
+ pos <<= 1;
+ }
+ WeekDays::from_bits(res).unwrap()
+ };
+
+ if let (i, Some((_, endday))) = opt(pair(tag(".."), parse_weekday))(i)? {
+ let start = startday.bits();
+ let end = endday.bits();
+ if start > end {
+ let set1 = generate_range(start, WeekDays::SUNDAY.bits());
+ let set2 = generate_range(WeekDays::MONDAY.bits(), end);
+ Ok((i, set1 | set2))
+ } else {
+ Ok((i, generate_range(start, end)))
+ }
+ } else {
+ Ok((i, startday))
+ }
+}
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 05/14] proxmox-time: split DateTimeValue into own file
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (3 preceding siblings ...)
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 04/14] proxmox-time: move WeekDays into own file Dominik Csapak
@ 2021-11-30 12:11 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 06/14] proxmox-time: move parse_daily_duration to daily_duration.rs Dominik Csapak
` (10 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:11 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/date_time_value.rs | 82 ++++++++++++++++++++++++++++
proxmox-time/src/lib.rs | 2 +
proxmox-time/src/parse_time.rs | 1 +
proxmox-time/src/time.rs | 84 +----------------------------
4 files changed, 86 insertions(+), 83 deletions(-)
create mode 100644 proxmox-time/src/date_time_value.rs
diff --git a/proxmox-time/src/date_time_value.rs b/proxmox-time/src/date_time_value.rs
new file mode 100644
index 0000000..c3c2035
--- /dev/null
+++ b/proxmox-time/src/date_time_value.rs
@@ -0,0 +1,82 @@
+#[derive(Debug, Clone)]
+pub(crate) enum DateTimeValue {
+ Single(u32),
+ Range(u32, u32),
+ Repeated(u32, u32, Option<u32>),
+}
+
+impl DateTimeValue {
+ // Test if the entry contains the value
+ pub fn contains(&self, value: u32) -> bool {
+ match self {
+ DateTimeValue::Single(v) => *v == value,
+ DateTimeValue::Range(start, end) => value >= *start && value <= *end,
+ DateTimeValue::Repeated(start, repetition, opt_end) => {
+ if value >= *start {
+ if *repetition > 0 {
+ let offset = value - start;
+ let res = offset % repetition == 0;
+ if let Some(end) = opt_end {
+ res && value <= *end
+ } else {
+ res
+ }
+ } else {
+ *start == value
+ }
+ } else {
+ false
+ }
+ }
+ }
+ }
+
+ pub fn list_contains(list: &[DateTimeValue], value: u32) -> bool {
+ list.iter().any(|spec| spec.contains(value))
+ }
+
+ // Find an return an entry greater than value
+ pub fn find_next(list: &[DateTimeValue], value: u32) -> Option<u32> {
+ let mut next: Option<u32> = None;
+ let mut set_next = |v: u32| {
+ if let Some(n) = next {
+ if v < n { next = Some(v); }
+ } else {
+ next = Some(v);
+ }
+ };
+ for spec in list {
+ match spec {
+ DateTimeValue::Single(v) => {
+ if *v > value { set_next(*v); }
+ }
+ DateTimeValue::Range(start, end) => {
+ if value < *start {
+ set_next(*start);
+ } else {
+ let n = value + 1;
+ if n >= *start && n <= *end {
+ set_next(n);
+ }
+ }
+ }
+ DateTimeValue::Repeated(start, repetition, opt_end) => {
+ if value < *start {
+ set_next(*start);
+ } else if *repetition > 0 {
+ let n = start + ((value - start + repetition) / repetition) * repetition;
+ if let Some(end) = opt_end {
+ if n <= *end {
+ set_next(n);
+ }
+ } else {
+ set_next(n);
+ }
+ }
+ }
+ }
+ }
+
+ next
+ }
+}
diff --git a/proxmox-time/src/lib.rs b/proxmox-time/src/lib.rs
index bce4b56..3d888a2 100644
--- a/proxmox-time/src/lib.rs
+++ b/proxmox-time/src/lib.rs
@@ -15,6 +15,8 @@ pub use time::*;
pub(crate) mod parse_helpers;
+pub(crate) mod date_time_value;
+
mod week_days;
pub use week_days::*;
diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs
index 6dde4ae..00a9241 100644
--- a/proxmox-time/src/parse_time.rs
+++ b/proxmox-time/src/parse_time.rs
@@ -17,6 +17,7 @@ use nom::{
use crate::parse_helpers::{parse_complete_line, parse_error, parse_hm_time, parse_time_comp, parse_u64, IResult};
use crate::{parse_weekdays_range, WeekDays};
+use crate::date_time_value::DateTimeValue;
lazy_static! {
static ref TIME_SPAN_UNITS: HashMap<&'static str, f64> = {
diff --git a/proxmox-time/src/time.rs b/proxmox-time/src/time.rs
index 2b2a936..7b9625f 100644
--- a/proxmox-time/src/time.rs
+++ b/proxmox-time/src/time.rs
@@ -2,94 +2,12 @@ use std::convert::TryInto;
use anyhow::Error;
+use crate::date_time_value::DateTimeValue;
use crate::TmEditor;
use crate::WeekDays;
use crate::{parse_calendar_event, parse_time_span};
-#[derive(Debug, Clone)]
-pub(crate) enum DateTimeValue {
- Single(u32),
- Range(u32, u32),
- Repeated(u32, u32, Option<u32>),
-}
-
-impl DateTimeValue {
- // Test if the entry contains the value
- pub fn contains(&self, value: u32) -> bool {
- match self {
- DateTimeValue::Single(v) => *v == value,
- DateTimeValue::Range(start, end) => value >= *start && value <= *end,
- DateTimeValue::Repeated(start, repetition, opt_end) => {
- if value >= *start {
- if *repetition > 0 {
- let offset = value - start;
- let res = offset % repetition == 0;
- if let Some(end) = opt_end {
- res && value <= *end
- } else {
- res
- }
- } else {
- *start == value
- }
- } else {
- false
- }
- }
- }
- }
-
- pub fn list_contains(list: &[DateTimeValue], value: u32) -> bool {
- list.iter().any(|spec| spec.contains(value))
- }
-
- // Find an return an entry greater than value
- pub fn find_next(list: &[DateTimeValue], value: u32) -> Option<u32> {
- let mut next: Option<u32> = None;
- let mut set_next = |v: u32| {
- if let Some(n) = next {
- if v < n { next = Some(v); }
- } else {
- next = Some(v);
- }
- };
- for spec in list {
- match spec {
- DateTimeValue::Single(v) => {
- if *v > value { set_next(*v); }
- }
- DateTimeValue::Range(start, end) => {
- if value < *start {
- set_next(*start);
- } else {
- let n = value + 1;
- if n >= *start && n <= *end {
- set_next(n);
- }
- }
- }
- DateTimeValue::Repeated(start, repetition, opt_end) => {
- if value < *start {
- set_next(*start);
- } else if *repetition > 0 {
- let n = start + ((value - start + repetition) / repetition) * repetition;
- if let Some(end) = opt_end {
- if n <= *end {
- set_next(n);
- }
- } else {
- set_next(n);
- }
- }
- }
- }
- }
-
- next
- }
-}
-
/// Calendar events may be used to refer to one or more points in time in a
/// single expression. They are designed after the systemd.time Calendar Events
/// specification, but are not guaranteed to be 100% compatible.
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 06/14] proxmox-time: move parse_daily_duration to daily_duration.rs
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (4 preceding siblings ...)
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 05/14] proxmox-time: split DateTimeValue " Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 07/14] proxmox-time: daily_duration.rs: rustfmt Dominik Csapak
` (9 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/daily_duration.rs | 54 ++++++++++++++++++++++++++++--
proxmox-time/src/parse_time.rs | 43 ------------------------
2 files changed, 51 insertions(+), 46 deletions(-)
diff --git a/proxmox-time/src/daily_duration.rs b/proxmox-time/src/daily_duration.rs
index 2f4b03d..d5e0d90 100644
--- a/proxmox-time/src/daily_duration.rs
+++ b/proxmox-time/src/daily_duration.rs
@@ -2,10 +2,15 @@ use std::cmp::{Ordering, PartialOrd};
use std::convert::{TryFrom, TryInto};
use anyhow::Error;
+use nom::{
+ bytes::complete::tag,
+ character::complete::space0,
+ error::context,
+ multi::separated_nonempty_list,
+};
-use crate::{TmEditor, WeekDays};
-
-pub use super::parse_time::parse_daily_duration;
+use crate::parse_helpers::{parse_complete_line, parse_error, parse_hm_time, IResult};
+use crate::{parse_weekdays_range, TmEditor, WeekDays};
/// Time of Day (hour with minute)
#[derive(Default, PartialEq, Clone, Debug)]
@@ -79,6 +84,49 @@ impl DailyDuration {
}
}
+/// Parse a [DailyDuration]
+pub fn parse_daily_duration(i: &str) -> Result<DailyDuration, Error> {
+ parse_complete_line("daily duration", i, parse_daily_duration_incomplete)
+}
+
+fn parse_daily_duration_incomplete(mut i: &str) -> IResult<&str, DailyDuration> {
+ let mut duration = DailyDuration::default();
+
+ if i.starts_with(|c: char| char::is_ascii_alphabetic(&c)) {
+ let (n, range_list) = context(
+ "weekday range list",
+ separated_nonempty_list(tag(","), parse_weekdays_range),
+ )(i)?;
+
+ i = space0(n)?.0;
+
+ for range in range_list {
+ duration.days.insert(range);
+ }
+ }
+
+ let (i, start) = parse_hm_time(i)?;
+
+ let i = space0(i)?.0;
+
+ let (i, _) = tag("-")(i)?;
+
+ let i = space0(i)?.0;
+
+ let end_time_start = i;
+
+ let (i, end) = parse_hm_time(i)?;
+
+ if start > end {
+ return Err(parse_error(end_time_start, "end time before start time"));
+ }
+
+ duration.start = start;
+ duration.end = end;
+
+ Ok((i, duration))
+}
+
#[cfg(test)]
mod test {
diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs
index 00a9241..adaf7ac 100644
--- a/proxmox-time/src/parse_time.rs
+++ b/proxmox-time/src/parse_time.rs
@@ -375,46 +375,3 @@ fn parse_time_span_incomplete(mut i: &str) -> IResult<&str, TimeSpan> {
Ok((i, ts))
}
-
-/// Parse a [DailyDuration]
-pub fn parse_daily_duration(i: &str) -> Result<DailyDuration, Error> {
- parse_complete_line("daily duration", i, parse_daily_duration_incomplete)
-}
-
-fn parse_daily_duration_incomplete(mut i: &str) -> IResult<&str, DailyDuration> {
-
- let mut duration = DailyDuration::default();
-
- if i.starts_with(|c: char| char::is_ascii_alphabetic(&c)) {
-
- let (n, range_list) = context(
- "weekday range list",
- separated_nonempty_list(tag(","), parse_weekdays_range)
- )(i)?;
-
- i = space0(n)?.0;
-
- for range in range_list { duration.days.insert(range); }
- }
-
- let (i, start) = parse_hm_time(i)?;
-
- let i = space0(i)?.0;
-
- let (i, _) = tag("-")(i)?;
-
- let i = space0(i)?.0;
-
- let end_time_start = i;
-
- let (i, end) = parse_hm_time(i)?;
-
- if start > end {
- return Err(parse_error(end_time_start, "end time before start time"));
- }
-
- duration.start = start;
- duration.end = end;
-
- Ok((i, duration))
-}
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 07/14] proxmox-time: daily_duration.rs: rustfmt
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (5 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 06/14] proxmox-time: move parse_daily_duration to daily_duration.rs Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 08/14] proxmox-time: move CalendarEvent into calendar_events.rs Dominik Csapak
` (8 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/daily_duration.rs | 76 ++++++++++++++++++------------
1 file changed, 46 insertions(+), 30 deletions(-)
diff --git a/proxmox-time/src/daily_duration.rs b/proxmox-time/src/daily_duration.rs
index d5e0d90..54037ba 100644
--- a/proxmox-time/src/daily_duration.rs
+++ b/proxmox-time/src/daily_duration.rs
@@ -23,7 +23,7 @@ impl PartialOrd for HmTime {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let mut order = self.hour.cmp(&other.hour);
if order == Ordering::Equal {
- order = self.minute.cmp(&other.minute);
+ order = self.minute.cmp(&other.minute);
}
Some(order)
}
@@ -39,10 +39,8 @@ pub struct DailyDuration {
}
impl DailyDuration {
-
/// Test it time is within this frame
pub fn time_match(&self, epoch: i64, utc: bool) -> Result<bool, Error> {
-
let t = TmEditor::with_epoch(epoch, utc)?;
Ok(self.time_match_with_tm_editor(&t))
@@ -55,18 +53,17 @@ impl DailyDuration {
pub fn time_match_with_tm_editor(&self, t: &TmEditor) -> bool {
let all_days = self.days.is_empty() || self.days.is_all();
- if !all_days { // match day first
+ if !all_days {
+ // match day first
match u32::try_from(t.day_num()) {
- Ok(day_num) => {
- match WeekDays::from_bits(1<<day_num) {
- Some(day) => {
- if !self.days.contains(day) {
- return false;
- }
+ Ok(day_num) => match WeekDays::from_bits(1 << day_num) {
+ Some(day) => {
+ if !self.days.contains(day) {
+ return false;
}
- None => return false,
}
- }
+ None => return false,
+ },
Err(_) => return false,
}
}
@@ -136,43 +133,62 @@ mod test {
fn test_parse(
duration_str: &str,
- start_h: u32, start_m: u32,
- end_h: u32, end_m: u32,
+ start_h: u32,
+ start_m: u32,
+ end_h: u32,
+ end_m: u32,
days: &[usize],
) -> Result<(), Error> {
let mut day_bits = 0;
- for day in days { day_bits |= 1<<day; }
+ for day in days {
+ day_bits |= 1 << day;
+ }
let expected_days = WeekDays::from_bits(day_bits).unwrap();
let duration = parse_daily_duration(duration_str)?;
if duration.start.hour != start_h {
- bail!("start hour missmatch, extected {}, got {:?}", start_h, duration);
+ bail!(
+ "start hour missmatch, extected {}, got {:?}",
+ start_h,
+ duration
+ );
}
if duration.start.minute != start_m {
- bail!("start minute missmatch, extected {}, got {:?}", start_m, duration);
+ bail!(
+ "start minute missmatch, extected {}, got {:?}",
+ start_m,
+ duration
+ );
}
if duration.end.hour != end_h {
bail!("end hour missmatch, extected {}, got {:?}", end_h, duration);
}
if duration.end.minute != end_m {
- bail!("end minute missmatch, extected {}, got {:?}", end_m, duration);
+ bail!(
+ "end minute missmatch, extected {}, got {:?}",
+ end_m,
+ duration
+ );
}
if duration.days != expected_days {
- bail!("weekday missmatch, extected {:?}, got {:?}", expected_days, duration);
+ bail!(
+ "weekday missmatch, extected {:?}, got {:?}",
+ expected_days,
+ duration
+ );
}
Ok(())
}
const fn make_test_time(mday: i32, hour: i32, min: i32) -> i64 {
- (mday*3600*24 + hour*3600 + min*60) as i64
+ (mday * 3600 * 24 + hour * 3600 + min * 60) as i64
}
#[test]
fn test_daily_duration_parser() -> Result<(), Error> {
-
assert!(parse_daily_duration("").is_err());
assert!(parse_daily_duration(" 8-12").is_err());
assert!(parse_daily_duration("8:60-12").is_err());
@@ -186,8 +202,8 @@ mod test {
test_parse("8:05 - 12:20", 8, 5, 12, 20, &[])?;
test_parse("mon 8-12", 8, 0, 12, 0, &[0])?;
- test_parse("tue..fri 8-12", 8, 0, 12, 0, &[1,2,3,4])?;
- test_parse("sat,tue..thu,fri 8-12", 8, 0, 12, 0, &[1,2,3,4,5])?;
+ test_parse("tue..fri 8-12", 8, 0, 12, 0, &[1, 2, 3, 4])?;
+ test_parse("sat,tue..thu,fri 8-12", 8, 0, 12, 0, &[1, 2, 3, 4, 5])?;
Ok(())
}
@@ -196,25 +212,25 @@ mod test {
fn test_time_match() -> Result<(), Error> {
const THURSDAY_80_00: i64 = make_test_time(0, 8, 0);
const THURSDAY_12_00: i64 = make_test_time(0, 12, 0);
- const DAY: i64 = 3600*24;
+ const DAY: i64 = 3600 * 24;
let duration = parse_daily_duration("thu..fri 8:05-12")?;
assert!(!duration.time_match(THURSDAY_80_00, true)?);
assert!(!duration.time_match(THURSDAY_80_00 + DAY, true)?);
- assert!(!duration.time_match(THURSDAY_80_00 + 2*DAY, true)?);
+ assert!(!duration.time_match(THURSDAY_80_00 + 2 * DAY, true)?);
- assert!(duration.time_match(THURSDAY_80_00 + 5*60, true)?);
- assert!(duration.time_match(THURSDAY_80_00 + 5*60 + DAY, true)?);
- assert!(!duration.time_match(THURSDAY_80_00 + 5*60 + 2*DAY, true)?);
+ assert!(duration.time_match(THURSDAY_80_00 + 5 * 60, true)?);
+ assert!(duration.time_match(THURSDAY_80_00 + 5 * 60 + DAY, true)?);
+ assert!(!duration.time_match(THURSDAY_80_00 + 5 * 60 + 2 * DAY, true)?);
assert!(duration.time_match(THURSDAY_12_00 - 1, true)?);
assert!(duration.time_match(THURSDAY_12_00 - 1 + DAY, true)?);
- assert!(!duration.time_match(THURSDAY_12_00 - 1 + 2*DAY, true)?);
+ assert!(!duration.time_match(THURSDAY_12_00 - 1 + 2 * DAY, true)?);
assert!(!duration.time_match(THURSDAY_12_00, true)?);
assert!(!duration.time_match(THURSDAY_12_00 + DAY, true)?);
- assert!(!duration.time_match(THURSDAY_12_00 + 2*DAY, true)?);
+ assert!(!duration.time_match(THURSDAY_12_00 + 2 * DAY, true)?);
Ok(())
}
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 08/14] proxmox-time: move CalendarEvent into calendar_events.rs
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (6 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 07/14] proxmox-time: daily_duration.rs: rustfmt Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 09/14] proxmox-time: move TimeSpan into time_span.rs Dominik Csapak
` (7 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
and all relevant parsing functions as well
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/calendar_event.rs | 429 +++++++++++++++++++++++++++++
proxmox-time/src/lib.rs | 3 +
proxmox-time/src/parse_time.rs | 220 ---------------
proxmox-time/src/time.rs | 160 +----------
4 files changed, 433 insertions(+), 379 deletions(-)
create mode 100644 proxmox-time/src/calendar_event.rs
diff --git a/proxmox-time/src/calendar_event.rs b/proxmox-time/src/calendar_event.rs
new file mode 100644
index 0000000..1c21a84
--- /dev/null
+++ b/proxmox-time/src/calendar_event.rs
@@ -0,0 +1,429 @@
+use std::convert::TryInto;
+
+use anyhow::Error;
+use nom::{
+ bytes::complete::tag,
+ character::complete::space0,
+ combinator::opt,
+ error::context,
+ multi::separated_nonempty_list,
+ sequence::{preceded, terminated, tuple},
+};
+
+use crate::date_time_value::DateTimeValue;
+use crate::parse_helpers::{parse_complete_line, parse_error, parse_time_comp, IResult};
+use crate::{parse_weekdays_range, TmEditor, WeekDays};
+
+/// Calendar events may be used to refer to one or more points in time in a
+/// single expression. They are designed after the systemd.time Calendar Events
+/// specification, but are not guaranteed to be 100% compatible.
+#[derive(Default, Clone, Debug)]
+pub struct CalendarEvent {
+ /// the days in a week this event should trigger
+ pub(crate) days: WeekDays,
+ /// the second(s) this event should trigger
+ pub(crate) second: Vec<DateTimeValue>, // todo: support float values
+ /// the minute(s) this event should trigger
+ pub(crate) minute: Vec<DateTimeValue>,
+ /// the hour(s) this event should trigger
+ pub(crate) hour: Vec<DateTimeValue>,
+ /// the day(s) in a month this event should trigger
+ pub(crate) day: Vec<DateTimeValue>,
+ /// the month(s) in a year this event should trigger
+ pub(crate) month: Vec<DateTimeValue>,
+ /// the years(s) this event should trigger
+ pub(crate) year: Vec<DateTimeValue>,
+}
+
+/// Verify the format of the [CalendarEvent]
+pub fn verify_calendar_event(i: &str) -> Result<(), Error> {
+ parse_calendar_event(i)?;
+ Ok(())
+}
+
+/// Compute the next event
+pub fn compute_next_event(
+ event: &CalendarEvent,
+ last: i64,
+ utc: bool,
+) -> Result<Option<i64>, Error> {
+
+ let last = last + 1; // at least one second later
+
+ let all_days = event.days.is_empty() || event.days.is_all();
+
+ let mut t = TmEditor::with_epoch(last, utc)?;
+
+ let mut count = 0;
+
+ loop {
+ // cancel after 1000 loops
+ if count > 1000 {
+ return Ok(None);
+ } else {
+ count += 1;
+ }
+
+ if !event.year.is_empty() {
+ let year: u32 = t.year().try_into()?;
+ if !DateTimeValue::list_contains(&event.year, year) {
+ if let Some(n) = DateTimeValue::find_next(&event.year, year) {
+ t.add_years((n - year).try_into()?)?;
+ continue;
+ } else {
+ // if we have no valid year, we cannot find a correct timestamp
+ return Ok(None);
+ }
+ }
+ }
+
+ if !event.month.is_empty() {
+ let month: u32 = t.month().try_into()?;
+ if !DateTimeValue::list_contains(&event.month, month) {
+ if let Some(n) = DateTimeValue::find_next(&event.month, month) {
+ t.add_months((n - month).try_into()?)?;
+ } else {
+ // if we could not find valid month, retry next year
+ t.add_years(1)?;
+ }
+ continue;
+ }
+ }
+
+ if !event.day.is_empty() {
+ let day: u32 = t.day().try_into()?;
+ if !DateTimeValue::list_contains(&event.day, day) {
+ if let Some(n) = DateTimeValue::find_next(&event.day, day) {
+ t.add_days((n - day).try_into()?)?;
+ } else {
+ // if we could not find valid mday, retry next month
+ t.add_months(1)?;
+ }
+ continue;
+ }
+ }
+
+ if !all_days { // match day first
+ let day_num: u32 = t.day_num().try_into()?;
+ let day = WeekDays::from_bits(1<<day_num).unwrap();
+ if !event.days.contains(day) {
+ if let Some(n) = ((day_num+1)..7)
+ .find(|d| event.days.contains(WeekDays::from_bits(1<<d).unwrap()))
+ {
+ // try next day
+ t.add_days((n - day_num).try_into()?)?;
+ } else {
+ // try next week
+ t.add_days((7 - day_num).try_into()?)?;
+ }
+ continue;
+ }
+ }
+
+ // this day
+ if !event.hour.is_empty() {
+ let hour = t.hour().try_into()?;
+ if !DateTimeValue::list_contains(&event.hour, hour) {
+ if let Some(n) = DateTimeValue::find_next(&event.hour, hour) {
+ // test next hour
+ t.set_time(n.try_into()?, 0, 0)?;
+ } else {
+ // test next day
+ t.add_days(1)?;
+ }
+ continue;
+ }
+ }
+
+ // this hour
+ if !event.minute.is_empty() {
+ let minute = t.min().try_into()?;
+ if !DateTimeValue::list_contains(&event.minute, minute) {
+ if let Some(n) = DateTimeValue::find_next(&event.minute, minute) {
+ // test next minute
+ t.set_min_sec(n.try_into()?, 0)?;
+ } else {
+ // test next hour
+ t.set_time(t.hour() + 1, 0, 0)?;
+ }
+ continue;
+ }
+ }
+
+ // this minute
+ if !event.second.is_empty() {
+ let second = t.sec().try_into()?;
+ if !DateTimeValue::list_contains(&event.second, second) {
+ if let Some(n) = DateTimeValue::find_next(&event.second, second) {
+ // test next second
+ t.set_sec(n.try_into()?)?;
+ } else {
+ // test next min
+ t.set_min_sec(t.min() + 1, 0)?;
+ }
+ continue;
+ }
+ }
+
+ let next = t.into_epoch()?;
+ return Ok(Some(next))
+ }
+}
+
+/// Parse a [CalendarEvent]
+pub fn parse_calendar_event(i: &str) -> Result<CalendarEvent, Error> {
+ parse_complete_line("calendar event", i, parse_calendar_event_incomplete)
+}
+
+fn parse_calendar_event_incomplete(mut i: &str) -> IResult<&str, CalendarEvent> {
+ let mut has_dayspec = false;
+ let mut has_timespec = false;
+ let mut has_datespec = false;
+
+ let mut event = CalendarEvent::default();
+
+ if i.starts_with(|c: char| char::is_ascii_alphabetic(&c)) {
+ match i {
+ "minutely" => {
+ return Ok((
+ "",
+ CalendarEvent {
+ second: vec![DateTimeValue::Single(0)],
+ ..Default::default()
+ },
+ ));
+ }
+ "hourly" => {
+ return Ok((
+ "",
+ CalendarEvent {
+ minute: vec![DateTimeValue::Single(0)],
+ second: vec![DateTimeValue::Single(0)],
+ ..Default::default()
+ },
+ ));
+ }
+ "daily" => {
+ return Ok((
+ "",
+ CalendarEvent {
+ hour: vec![DateTimeValue::Single(0)],
+ minute: vec![DateTimeValue::Single(0)],
+ second: vec![DateTimeValue::Single(0)],
+ ..Default::default()
+ },
+ ));
+ }
+ "weekly" => {
+ return Ok((
+ "",
+ CalendarEvent {
+ hour: vec![DateTimeValue::Single(0)],
+ minute: vec![DateTimeValue::Single(0)],
+ second: vec![DateTimeValue::Single(0)],
+ days: WeekDays::MONDAY,
+ ..Default::default()
+ },
+ ));
+ }
+ "monthly" => {
+ return Ok((
+ "",
+ CalendarEvent {
+ hour: vec![DateTimeValue::Single(0)],
+ minute: vec![DateTimeValue::Single(0)],
+ second: vec![DateTimeValue::Single(0)],
+ day: vec![DateTimeValue::Single(1)],
+ ..Default::default()
+ },
+ ));
+ }
+ "yearly" | "annually" => {
+ return Ok((
+ "",
+ CalendarEvent {
+ hour: vec![DateTimeValue::Single(0)],
+ minute: vec![DateTimeValue::Single(0)],
+ second: vec![DateTimeValue::Single(0)],
+ day: vec![DateTimeValue::Single(1)],
+ month: vec![DateTimeValue::Single(1)],
+ ..Default::default()
+ },
+ ));
+ }
+ "quarterly" => {
+ return Ok((
+ "",
+ CalendarEvent {
+ hour: vec![DateTimeValue::Single(0)],
+ minute: vec![DateTimeValue::Single(0)],
+ second: vec![DateTimeValue::Single(0)],
+ day: vec![DateTimeValue::Single(1)],
+ month: vec![
+ DateTimeValue::Single(1),
+ DateTimeValue::Single(4),
+ DateTimeValue::Single(7),
+ DateTimeValue::Single(10),
+ ],
+ ..Default::default()
+ },
+ ));
+ }
+ "semiannually" | "semi-annually" => {
+ return Ok((
+ "",
+ CalendarEvent {
+ hour: vec![DateTimeValue::Single(0)],
+ minute: vec![DateTimeValue::Single(0)],
+ second: vec![DateTimeValue::Single(0)],
+ day: vec![DateTimeValue::Single(1)],
+ month: vec![DateTimeValue::Single(1), DateTimeValue::Single(7)],
+ ..Default::default()
+ },
+ ));
+ }
+ _ => { /* continue */ }
+ }
+
+ let (n, range_list) = context(
+ "weekday range list",
+ separated_nonempty_list(tag(","), parse_weekdays_range),
+ )(i)?;
+
+ has_dayspec = true;
+
+ i = space0(n)?.0;
+
+ for range in range_list {
+ event.days.insert(range);
+ }
+ }
+
+ if let (n, Some(date)) = opt(parse_date_spec)(i)? {
+ event.year = date.year;
+ event.month = date.month;
+ event.day = date.day;
+ has_datespec = true;
+ i = space0(n)?.0;
+ }
+
+ if let (n, Some(time)) = opt(parse_time_spec)(i)? {
+ event.hour = time.hour;
+ event.minute = time.minute;
+ event.second = time.second;
+ has_timespec = true;
+ i = n;
+ } else {
+ event.hour = vec![DateTimeValue::Single(0)];
+ event.minute = vec![DateTimeValue::Single(0)];
+ event.second = vec![DateTimeValue::Single(0)];
+ }
+
+ if !(has_dayspec || has_timespec || has_datespec) {
+ return Err(parse_error(i, "date or time specification"));
+ }
+
+ Ok((i, event))
+}
+
+struct TimeSpec {
+ hour: Vec<DateTimeValue>,
+ minute: Vec<DateTimeValue>,
+ second: Vec<DateTimeValue>,
+}
+
+struct DateSpec {
+ year: Vec<DateTimeValue>,
+ month: Vec<DateTimeValue>,
+ day: Vec<DateTimeValue>,
+}
+
+fn parse_date_time_comp(max: usize) -> impl Fn(&str) -> IResult<&str, DateTimeValue> {
+ move |i: &str| {
+ let (i, value) = parse_time_comp(max)(i)?;
+
+ if let (i, Some(end)) = opt(preceded(tag(".."), parse_time_comp(max)))(i)? {
+ if value > end {
+ return Err(parse_error(i, "range start is bigger than end"));
+ }
+ if let Some(time) = i.strip_prefix('/') {
+ let (time, repeat) = parse_time_comp(max)(time)?;
+ return Ok((time, DateTimeValue::Repeated(value, repeat, Some(end))));
+ }
+ return Ok((i, DateTimeValue::Range(value, end)));
+ }
+
+ if let Some(time) = i.strip_prefix('/') {
+ let (time, repeat) = parse_time_comp(max)(time)?;
+ Ok((time, DateTimeValue::Repeated(value, repeat, None)))
+ } else {
+ Ok((i, DateTimeValue::Single(value)))
+ }
+ }
+}
+
+fn parse_date_time_comp_list(
+ start: u32,
+ max: usize,
+) -> impl Fn(&str) -> IResult<&str, Vec<DateTimeValue>> {
+ move |i: &str| {
+ if let Some(rest) = i.strip_prefix('*') {
+ if let Some(time) = rest.strip_prefix('/') {
+ let (n, repeat) = parse_time_comp(max)(time)?;
+ if repeat > 0 {
+ return Ok((n, vec![DateTimeValue::Repeated(start, repeat, None)]));
+ }
+ }
+ return Ok((rest, Vec::new()));
+ }
+
+ separated_nonempty_list(tag(","), parse_date_time_comp(max))(i)
+ }
+}
+
+fn parse_time_spec(i: &str) -> IResult<&str, TimeSpec> {
+ let (i, (opt_hour, minute, opt_second)) = tuple((
+ opt(terminated(parse_date_time_comp_list(0, 24), tag(":"))),
+ parse_date_time_comp_list(0, 60),
+ opt(preceded(tag(":"), parse_date_time_comp_list(0, 60))),
+ ))(i)?;
+
+ let hour = opt_hour.unwrap_or_else(Vec::new);
+ let second = opt_second.unwrap_or_else(|| vec![DateTimeValue::Single(0)]);
+
+ Ok((
+ i,
+ TimeSpec {
+ hour,
+ minute,
+ second,
+ },
+ ))
+}
+
+fn parse_date_spec(i: &str) -> IResult<&str, DateSpec> {
+ // TODO: implement ~ for days (man systemd.time)
+ if let Ok((i, (year, month, day))) = tuple((
+ parse_date_time_comp_list(0, 2200), // the upper limit for systemd, stay compatible
+ preceded(tag("-"), parse_date_time_comp_list(1, 13)),
+ preceded(tag("-"), parse_date_time_comp_list(1, 32)),
+ ))(i)
+ {
+ Ok((i, DateSpec { year, month, day }))
+ } else if let Ok((i, (month, day))) = tuple((
+ parse_date_time_comp_list(1, 13),
+ preceded(tag("-"), parse_date_time_comp_list(1, 32)),
+ ))(i)
+ {
+ Ok((
+ i,
+ DateSpec {
+ year: Vec::new(),
+ month,
+ day,
+ },
+ ))
+ } else {
+ Err(parse_error(i, "invalid date spec"))
+ }
+}
diff --git a/proxmox-time/src/lib.rs b/proxmox-time/src/lib.rs
index 3d888a2..0436628 100644
--- a/proxmox-time/src/lib.rs
+++ b/proxmox-time/src/lib.rs
@@ -17,6 +17,9 @@ pub(crate) mod parse_helpers;
pub(crate) mod date_time_value;
+mod calendar_event;
+pub use calendar_event::*;
+
mod week_days;
pub use week_days::*;
diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs
index adaf7ac..51c0486 100644
--- a/proxmox-time/src/parse_time.rs
+++ b/proxmox-time/src/parse_time.rs
@@ -88,226 +88,6 @@ lazy_static! {
};
}
-struct TimeSpec {
- hour: Vec<DateTimeValue>,
- minute: Vec<DateTimeValue>,
- second: Vec<DateTimeValue>,
-}
-
-struct DateSpec {
- year: Vec<DateTimeValue>,
- month: Vec<DateTimeValue>,
- day: Vec<DateTimeValue>,
-}
-
-fn parse_date_time_comp(max: usize) -> impl Fn(&str) -> IResult<&str, DateTimeValue> {
- move |i: &str| {
- let (i, value) = parse_time_comp(max)(i)?;
-
- if let (i, Some(end)) = opt(preceded(tag(".."), parse_time_comp(max)))(i)? {
- if value > end {
- return Err(parse_error(i, "range start is bigger than end"));
- }
- if let Some(time) = i.strip_prefix('/') {
- let (time, repeat) = parse_time_comp(max)(time)?;
- return Ok((time, DateTimeValue::Repeated(value, repeat, Some(end))));
- }
- return Ok((i, DateTimeValue::Range(value, end)));
- }
-
- if let Some(time) = i.strip_prefix('/') {
- let (time, repeat) = parse_time_comp(max)(time)?;
- Ok((time, DateTimeValue::Repeated(value, repeat, None)))
- } else {
- Ok((i, DateTimeValue::Single(value)))
- }
- }
-}
-
-fn parse_date_time_comp_list(start: u32, max: usize) -> impl Fn(&str) -> IResult<&str, Vec<DateTimeValue>> {
- move |i: &str| {
- if let Some(rest) = i.strip_prefix('*') {
- if let Some(time) = rest.strip_prefix('/') {
- let (n, repeat) = parse_time_comp(max)(time)?;
- if repeat > 0 {
- return Ok((n, vec![DateTimeValue::Repeated(start, repeat, None)]));
- }
- }
- return Ok((rest, Vec::new()));
- }
-
- separated_nonempty_list(tag(","), parse_date_time_comp(max))(i)
- }
-}
-
-fn parse_time_spec(i: &str) -> IResult<&str, TimeSpec> {
-
- let (i, (opt_hour, minute, opt_second)) = tuple((
- opt(terminated(parse_date_time_comp_list(0, 24), tag(":"))),
- parse_date_time_comp_list(0, 60),
- opt(preceded(tag(":"), parse_date_time_comp_list(0, 60))),
- ))(i)?;
-
- let hour = opt_hour.unwrap_or_else(Vec::new);
- let second = opt_second.unwrap_or_else(|| vec![DateTimeValue::Single(0)]);
-
- Ok((i, TimeSpec { hour, minute, second }))
-}
-
-fn parse_date_spec(i: &str) -> IResult<&str, DateSpec> {
-
- // TODO: implement ~ for days (man systemd.time)
- if let Ok((i, (year, month, day))) = tuple((
- parse_date_time_comp_list(0, 2200), // the upper limit for systemd, stay compatible
- preceded(tag("-"), parse_date_time_comp_list(1, 13)),
- preceded(tag("-"), parse_date_time_comp_list(1, 32)),
- ))(i) {
- Ok((i, DateSpec { year, month, day }))
- } else if let Ok((i, (month, day))) = tuple((
- parse_date_time_comp_list(1, 13),
- preceded(tag("-"), parse_date_time_comp_list(1, 32)),
- ))(i) {
- Ok((i, DateSpec { year: Vec::new(), month, day }))
- } else {
- Err(parse_error(i, "invalid date spec"))
- }
-}
-
-/// Parse a [CalendarEvent]
-pub fn parse_calendar_event(i: &str) -> Result<CalendarEvent, Error> {
- parse_complete_line("calendar event", i, parse_calendar_event_incomplete)
-}
-
-fn parse_calendar_event_incomplete(mut i: &str) -> IResult<&str, CalendarEvent> {
-
- let mut has_dayspec = false;
- let mut has_timespec = false;
- let mut has_datespec = false;
-
- let mut event = CalendarEvent::default();
-
- if i.starts_with(|c: char| char::is_ascii_alphabetic(&c)) {
-
- match i {
- "minutely" => {
- return Ok(("", CalendarEvent {
- second: vec![DateTimeValue::Single(0)],
- ..Default::default()
- }));
- }
- "hourly" => {
- return Ok(("", CalendarEvent {
- minute: vec![DateTimeValue::Single(0)],
- second: vec![DateTimeValue::Single(0)],
- ..Default::default()
- }));
- }
- "daily" => {
- return Ok(("", CalendarEvent {
- hour: vec![DateTimeValue::Single(0)],
- minute: vec![DateTimeValue::Single(0)],
- second: vec![DateTimeValue::Single(0)],
- ..Default::default()
- }));
- }
- "weekly" => {
- return Ok(("", CalendarEvent {
- hour: vec![DateTimeValue::Single(0)],
- minute: vec![DateTimeValue::Single(0)],
- second: vec![DateTimeValue::Single(0)],
- days: WeekDays::MONDAY,
- ..Default::default()
- }));
- }
- "monthly" => {
- return Ok(("", CalendarEvent {
- hour: vec![DateTimeValue::Single(0)],
- minute: vec![DateTimeValue::Single(0)],
- second: vec![DateTimeValue::Single(0)],
- day: vec![DateTimeValue::Single(1)],
- ..Default::default()
- }));
- }
- "yearly" | "annually" => {
- return Ok(("", CalendarEvent {
- hour: vec![DateTimeValue::Single(0)],
- minute: vec![DateTimeValue::Single(0)],
- second: vec![DateTimeValue::Single(0)],
- day: vec![DateTimeValue::Single(1)],
- month: vec![DateTimeValue::Single(1)],
- ..Default::default()
- }));
- }
- "quarterly" => {
- return Ok(("", CalendarEvent {
- hour: vec![DateTimeValue::Single(0)],
- minute: vec![DateTimeValue::Single(0)],
- second: vec![DateTimeValue::Single(0)],
- day: vec![DateTimeValue::Single(1)],
- month: vec![
- DateTimeValue::Single(1),
- DateTimeValue::Single(4),
- DateTimeValue::Single(7),
- DateTimeValue::Single(10),
- ],
- ..Default::default()
- }));
- }
- "semiannually" | "semi-annually" => {
- return Ok(("", CalendarEvent {
- hour: vec![DateTimeValue::Single(0)],
- minute: vec![DateTimeValue::Single(0)],
- second: vec![DateTimeValue::Single(0)],
- day: vec![DateTimeValue::Single(1)],
- month: vec![
- DateTimeValue::Single(1),
- DateTimeValue::Single(7),
- ],
- ..Default::default()
- }));
- }
- _ => { /* continue */ }
- }
-
- let (n, range_list) = context(
- "weekday range list",
- separated_nonempty_list(tag(","), parse_weekdays_range)
- )(i)?;
-
- has_dayspec = true;
-
- i = space0(n)?.0;
-
- for range in range_list { event.days.insert(range); }
- }
-
- if let (n, Some(date)) = opt(parse_date_spec)(i)? {
- event.year = date.year;
- event.month = date.month;
- event.day = date.day;
- has_datespec = true;
- i = space0(n)?.0;
- }
-
- if let (n, Some(time)) = opt(parse_time_spec)(i)? {
- event.hour = time.hour;
- event.minute = time.minute;
- event.second = time.second;
- has_timespec = true;
- i = n;
- } else {
- event.hour = vec![DateTimeValue::Single(0)];
- event.minute = vec![DateTimeValue::Single(0)];
- event.second = vec![DateTimeValue::Single(0)];
- }
-
- if !(has_dayspec || has_timespec || has_datespec) {
- return Err(parse_error(i, "date or time specification"));
- }
-
- Ok((i, event))
-}
-
fn parse_time_unit(i: &str) -> IResult<&str, &str> {
let (n, text) = take_while1(|c: char| char::is_ascii_alphabetic(&c) || c == 'µ')(i)?;
if TIME_SPAN_UNITS.contains_key(&text) {
diff --git a/proxmox-time/src/time.rs b/proxmox-time/src/time.rs
index 7b9625f..1c45a09 100644
--- a/proxmox-time/src/time.rs
+++ b/proxmox-time/src/time.rs
@@ -1,33 +1,10 @@
-use std::convert::TryInto;
-
use anyhow::Error;
use crate::date_time_value::DateTimeValue;
use crate::TmEditor;
use crate::WeekDays;
-use crate::{parse_calendar_event, parse_time_span};
-
-/// Calendar events may be used to refer to one or more points in time in a
-/// single expression. They are designed after the systemd.time Calendar Events
-/// specification, but are not guaranteed to be 100% compatible.
-#[derive(Default, Clone, Debug)]
-pub struct CalendarEvent {
- /// the days in a week this event should trigger
- pub(crate) days: WeekDays,
- /// the second(s) this event should trigger
- pub(crate) second: Vec<DateTimeValue>, // todo: support float values
- /// the minute(s) this event should trigger
- pub(crate) minute: Vec<DateTimeValue>,
- /// the hour(s) this event should trigger
- pub(crate) hour: Vec<DateTimeValue>,
- /// the day(s) in a month this event should trigger
- pub(crate) day: Vec<DateTimeValue>,
- /// the month(s) in a year this event should trigger
- pub(crate) month: Vec<DateTimeValue>,
- /// the years(s) this event should trigger
- pub(crate) year: Vec<DateTimeValue>,
-}
+use crate::{compute_next_event, parse_calendar_event, parse_time_span};
/// A time spans defines a time duration
#[derive(Default, Clone, Debug)]
@@ -148,141 +125,6 @@ pub fn verify_time_span(i: &str) -> Result<(), Error> {
Ok(())
}
-/// Verify the format of the [CalendarEvent]
-pub fn verify_calendar_event(i: &str) -> Result<(), Error> {
- parse_calendar_event(i)?;
- Ok(())
-}
-
-/// Compute the next event
-pub fn compute_next_event(
- event: &CalendarEvent,
- last: i64,
- utc: bool,
-) -> Result<Option<i64>, Error> {
-
- let last = last + 1; // at least one second later
-
- let all_days = event.days.is_empty() || event.days.is_all();
-
- let mut t = TmEditor::with_epoch(last, utc)?;
-
- let mut count = 0;
-
- loop {
- // cancel after 1000 loops
- if count > 1000 {
- return Ok(None);
- } else {
- count += 1;
- }
-
- if !event.year.is_empty() {
- let year: u32 = t.year().try_into()?;
- if !DateTimeValue::list_contains(&event.year, year) {
- if let Some(n) = DateTimeValue::find_next(&event.year, year) {
- t.add_years((n - year).try_into()?)?;
- continue;
- } else {
- // if we have no valid year, we cannot find a correct timestamp
- return Ok(None);
- }
- }
- }
-
- if !event.month.is_empty() {
- let month: u32 = t.month().try_into()?;
- if !DateTimeValue::list_contains(&event.month, month) {
- if let Some(n) = DateTimeValue::find_next(&event.month, month) {
- t.add_months((n - month).try_into()?)?;
- } else {
- // if we could not find valid month, retry next year
- t.add_years(1)?;
- }
- continue;
- }
- }
-
- if !event.day.is_empty() {
- let day: u32 = t.day().try_into()?;
- if !DateTimeValue::list_contains(&event.day, day) {
- if let Some(n) = DateTimeValue::find_next(&event.day, day) {
- t.add_days((n - day).try_into()?)?;
- } else {
- // if we could not find valid mday, retry next month
- t.add_months(1)?;
- }
- continue;
- }
- }
-
- if !all_days { // match day first
- let day_num: u32 = t.day_num().try_into()?;
- let day = WeekDays::from_bits(1<<day_num).unwrap();
- if !event.days.contains(day) {
- if let Some(n) = ((day_num+1)..7)
- .find(|d| event.days.contains(WeekDays::from_bits(1<<d).unwrap()))
- {
- // try next day
- t.add_days((n - day_num).try_into()?)?;
- } else {
- // try next week
- t.add_days((7 - day_num).try_into()?)?;
- }
- continue;
- }
- }
-
- // this day
- if !event.hour.is_empty() {
- let hour = t.hour().try_into()?;
- if !DateTimeValue::list_contains(&event.hour, hour) {
- if let Some(n) = DateTimeValue::find_next(&event.hour, hour) {
- // test next hour
- t.set_time(n.try_into()?, 0, 0)?;
- } else {
- // test next day
- t.add_days(1)?;
- }
- continue;
- }
- }
-
- // this hour
- if !event.minute.is_empty() {
- let minute = t.min().try_into()?;
- if !DateTimeValue::list_contains(&event.minute, minute) {
- if let Some(n) = DateTimeValue::find_next(&event.minute, minute) {
- // test next minute
- t.set_min_sec(n.try_into()?, 0)?;
- } else {
- // test next hour
- t.set_time(t.hour() + 1, 0, 0)?;
- }
- continue;
- }
- }
-
- // this minute
- if !event.second.is_empty() {
- let second = t.sec().try_into()?;
- if !DateTimeValue::list_contains(&event.second, second) {
- if let Some(n) = DateTimeValue::find_next(&event.second, second) {
- // test next second
- t.set_sec(n.try_into()?)?;
- } else {
- // test next min
- t.set_min_sec(t.min() + 1, 0)?;
- }
- continue;
- }
- }
-
- let next = t.into_epoch()?;
- return Ok(Some(next))
- }
-}
-
#[cfg(test)]
mod test {
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 09/14] proxmox-time: move TimeSpan into time_span.rs
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (7 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 08/14] proxmox-time: move CalendarEvent into calendar_events.rs Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 10/14] proxmox-time: move tests from time.rs to test.rs Dominik Csapak
` (6 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
and related parsing functions
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/lib.rs | 6 +-
proxmox-time/src/parse_time.rs | 157 -------------------
proxmox-time/src/time.rs | 129 +---------------
proxmox-time/src/time_span.rs | 265 +++++++++++++++++++++++++++++++++
4 files changed, 269 insertions(+), 288 deletions(-)
delete mode 100644 proxmox-time/src/parse_time.rs
create mode 100644 proxmox-time/src/time_span.rs
diff --git a/proxmox-time/src/lib.rs b/proxmox-time/src/lib.rs
index 0436628..cbb7008 100644
--- a/proxmox-time/src/lib.rs
+++ b/proxmox-time/src/lib.rs
@@ -7,9 +7,6 @@ use anyhow::{bail, format_err, Error};
mod tm_editor;
pub use tm_editor::*;
-mod parse_time;
-pub use parse_time::*;
-
mod time;
pub use time::*;
@@ -20,6 +17,9 @@ pub(crate) mod date_time_value;
mod calendar_event;
pub use calendar_event::*;
+mod time_span;
+pub use time_span::*;
+
mod week_days;
pub use week_days::*;
diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs
deleted file mode 100644
index 51c0486..0000000
--- a/proxmox-time/src/parse_time.rs
+++ /dev/null
@@ -1,157 +0,0 @@
-use std::collections::HashMap;
-
-use anyhow::{bail, Error};
-use lazy_static::lazy_static;
-
-use super::time::*;
-use super::daily_duration::*;
-
-use nom::{
- error::{context, ParseError, VerboseError},
- bytes::complete::{tag, take_while1},
- combinator::{map_res, all_consuming, opt, recognize},
- sequence::{pair, preceded, terminated, tuple},
- character::complete::{alpha1, space0, digit1},
- multi::separated_nonempty_list,
-};
-
-use crate::parse_helpers::{parse_complete_line, parse_error, parse_hm_time, parse_time_comp, parse_u64, IResult};
-use crate::{parse_weekdays_range, WeekDays};
-use crate::date_time_value::DateTimeValue;
-
-lazy_static! {
- static ref TIME_SPAN_UNITS: HashMap<&'static str, f64> = {
- let mut map = HashMap::new();
-
- let second = 1.0;
-
- map.insert("seconds", second);
- map.insert("second", second);
- map.insert("sec", second);
- map.insert("s", second);
-
- let msec = second / 1000.0;
-
- map.insert("msec", msec);
- map.insert("ms", msec);
-
- let usec = msec / 1000.0;
-
- map.insert("usec", usec);
- map.insert("us", usec);
- map.insert("µs", usec);
-
- let nsec = usec / 1000.0;
-
- map.insert("nsec", nsec);
- map.insert("ns", nsec);
-
- let minute = second * 60.0;
-
- map.insert("minutes", minute);
- map.insert("minute", minute);
- map.insert("min", minute);
- map.insert("m", minute);
-
- let hour = minute * 60.0;
-
- map.insert("hours", hour);
- map.insert("hour", hour);
- map.insert("hr", hour);
- map.insert("h", hour);
-
- let day = hour * 24.0 ;
-
- map.insert("days", day);
- map.insert("day", day);
- map.insert("d", day);
-
- let week = day * 7.0;
-
- map.insert("weeks", week);
- map.insert("week", week);
- map.insert("w", week);
-
- let month = 30.44 * day;
-
- map.insert("months", month);
- map.insert("month", month);
- map.insert("M", month);
-
- let year = 365.25 * day;
-
- map.insert("years", year);
- map.insert("year", year);
- map.insert("y", year);
-
- map
- };
-}
-
-fn parse_time_unit(i: &str) -> IResult<&str, &str> {
- let (n, text) = take_while1(|c: char| char::is_ascii_alphabetic(&c) || c == 'µ')(i)?;
- if TIME_SPAN_UNITS.contains_key(&text) {
- Ok((n, text))
- } else {
- Err(parse_error(text, "time unit"))
- }
-}
-
-
-/// Parse a [TimeSpan]
-pub fn parse_time_span(i: &str) -> Result<TimeSpan, Error> {
- parse_complete_line("time span", i, parse_time_span_incomplete)
-}
-
-fn parse_time_span_incomplete(mut i: &str) -> IResult<&str, TimeSpan> {
-
- let mut ts = TimeSpan::default();
-
- loop {
- i = space0(i)?.0;
- if i.is_empty() { break; }
- let (n, num) = parse_u64(i)?;
- i = space0(n)?.0;
-
- if let (n, Some(unit)) = opt(parse_time_unit)(i)? {
- i = n;
- match unit {
- "seconds" | "second" | "sec" | "s" => {
- ts.seconds += num;
- }
- "msec" | "ms" => {
- ts.msec += num;
- }
- "usec" | "us" | "µs" => {
- ts.usec += num;
- }
- "nsec" | "ns" => {
- ts.nsec += num;
- }
- "minutes" | "minute" | "min" | "m" => {
- ts.minutes += num;
- }
- "hours" | "hour" | "hr" | "h" => {
- ts.hours += num;
- }
- "days" | "day" | "d" => {
- ts.days += num;
- }
- "weeks" | "week" | "w" => {
- ts.weeks += num;
- }
- "months" | "month" | "M" => {
- ts.months += num;
- }
- "years" | "year" | "y" => {
- ts.years += num;
- }
- _ => return Err(parse_error(unit, "internal error")),
- }
- } else {
- ts.seconds += num;
- }
- }
-
- Ok((i, ts))
-}
diff --git a/proxmox-time/src/time.rs b/proxmox-time/src/time.rs
index 1c45a09..ac2f510 100644
--- a/proxmox-time/src/time.rs
+++ b/proxmox-time/src/time.rs
@@ -1,136 +1,9 @@
-use anyhow::Error;
-
-use crate::date_time_value::DateTimeValue;
-use crate::TmEditor;
-use crate::WeekDays;
-
-use crate::{compute_next_event, parse_calendar_event, parse_time_span};
-
-/// A time spans defines a time duration
-#[derive(Default, Clone, Debug)]
-pub struct TimeSpan {
- pub nsec: u64,
- pub usec: u64,
- pub msec: u64,
- pub seconds: u64,
- pub minutes: u64,
- pub hours: u64,
- pub days: u64,
- pub weeks: u64,
- pub months: u64,
- pub years: u64,
-}
-
-impl From<TimeSpan> for f64 {
- fn from(ts: TimeSpan) -> Self {
- (ts.seconds as f64) +
- ((ts.nsec as f64) / 1_000_000_000.0) +
- ((ts.usec as f64) / 1_000_000.0) +
- ((ts.msec as f64) / 1_000.0) +
- ((ts.minutes as f64) * 60.0) +
- ((ts.hours as f64) * 3600.0) +
- ((ts.days as f64) * 3600.0 * 24.0) +
- ((ts.weeks as f64) * 3600.0 * 24.0 * 7.0) +
- ((ts.months as f64) * 3600.0 * 24.0 * 30.44) +
- ((ts.years as f64) * 3600.0 * 24.0 * 365.25)
- }
-}
-
-impl From<std::time::Duration> for TimeSpan {
- fn from(duration: std::time::Duration) -> Self {
- let mut duration = duration.as_nanos();
- let nsec = (duration % 1000) as u64;
- duration /= 1000;
- let usec = (duration % 1000) as u64;
- duration /= 1000;
- let msec = (duration % 1000) as u64;
- duration /= 1000;
- let seconds = (duration % 60) as u64;
- duration /= 60;
- let minutes = (duration % 60) as u64;
- duration /= 60;
- let hours = (duration % 24) as u64;
- duration /= 24;
- let years = (duration as f64 / 365.25) as u64;
- let ydays = (duration as f64 % 365.25) as u64;
- let months = (ydays as f64 / 30.44) as u64;
- let mdays = (ydays as f64 % 30.44) as u64;
- let weeks = mdays / 7;
- let days = mdays % 7;
- Self {
- nsec,
- usec,
- msec,
- seconds,
- minutes,
- hours,
- days,
- weeks,
- months,
- years,
- }
- }
-}
-
-impl std::fmt::Display for TimeSpan {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
- let mut first = true;
- { // block scope for mutable borrows
- let mut do_write = |v: u64, unit: &str| -> Result<(), std::fmt::Error> {
- if !first {
- write!(f, " ")?;
- }
- first = false;
- write!(f, "{}{}", v, unit)
- };
- if self.years > 0 {
- do_write(self.years, "y")?;
- }
- if self.months > 0 {
- do_write(self.months, "m")?;
- }
- if self.weeks > 0 {
- do_write(self.weeks, "w")?;
- }
- if self.days > 0 {
- do_write(self.days, "d")?;
- }
- if self.hours > 0 {
- do_write(self.hours, "h")?;
- }
- if self.minutes > 0 {
- do_write(self.minutes, "min")?;
- }
- }
- if !first {
- write!(f, " ")?;
- }
- let seconds = self.seconds as f64 + (self.msec as f64 / 1000.0);
- if seconds >= 0.1 {
- if seconds >= 1.0 || !first {
- write!(f, "{:.0}s", seconds)?;
- } else {
- write!(f, "{:.1}s", seconds)?;
- }
- } else if first {
- write!(f, "<0.1s")?;
- }
- Ok(())
- }
-}
-
-/// Verify the format of the [TimeSpan]
-pub fn verify_time_span(i: &str) -> Result<(), Error> {
- parse_time_span(i)?;
- Ok(())
-}
-
#[cfg(test)]
mod test {
use anyhow::bail;
+ use crate::*;
- use super::*;
fn test_event(v: &'static str) -> Result<(), Error> {
match parse_calendar_event(v) {
diff --git a/proxmox-time/src/time_span.rs b/proxmox-time/src/time_span.rs
new file mode 100644
index 0000000..2f8cf59
--- /dev/null
+++ b/proxmox-time/src/time_span.rs
@@ -0,0 +1,265 @@
+use std::collections::HashMap;
+
+use anyhow::Error;
+use lazy_static::lazy_static;
+use nom::{bytes::complete::take_while1, character::complete::space0, combinator::opt};
+
+use crate::parse_helpers::{parse_complete_line, parse_error, parse_u64, IResult};
+
+lazy_static! {
+ static ref TIME_SPAN_UNITS: HashMap<&'static str, f64> = {
+ let mut map = HashMap::new();
+
+ let second = 1.0;
+
+ map.insert("seconds", second);
+ map.insert("second", second);
+ map.insert("sec", second);
+ map.insert("s", second);
+
+ let msec = second / 1000.0;
+
+ map.insert("msec", msec);
+ map.insert("ms", msec);
+
+ let usec = msec / 1000.0;
+
+ map.insert("usec", usec);
+ map.insert("us", usec);
+ map.insert("µs", usec);
+
+ let nsec = usec / 1000.0;
+
+ map.insert("nsec", nsec);
+ map.insert("ns", nsec);
+
+ let minute = second * 60.0;
+
+ map.insert("minutes", minute);
+ map.insert("minute", minute);
+ map.insert("min", minute);
+ map.insert("m", minute);
+
+ let hour = minute * 60.0;
+
+ map.insert("hours", hour);
+ map.insert("hour", hour);
+ map.insert("hr", hour);
+ map.insert("h", hour);
+
+ let day = hour * 24.0;
+
+ map.insert("days", day);
+ map.insert("day", day);
+ map.insert("d", day);
+
+ let week = day * 7.0;
+
+ map.insert("weeks", week);
+ map.insert("week", week);
+ map.insert("w", week);
+
+ let month = 30.44 * day;
+
+ map.insert("months", month);
+ map.insert("month", month);
+ map.insert("M", month);
+
+ let year = 365.25 * day;
+
+ map.insert("years", year);
+ map.insert("year", year);
+ map.insert("y", year);
+
+ map
+ };
+}
+
+/// A time spans defines a time duration
+#[derive(Default, Clone, Debug)]
+pub struct TimeSpan {
+ pub nsec: u64,
+ pub usec: u64,
+ pub msec: u64,
+ pub seconds: u64,
+ pub minutes: u64,
+ pub hours: u64,
+ pub days: u64,
+ pub weeks: u64,
+ pub months: u64,
+ pub years: u64,
+}
+
+impl From<TimeSpan> for f64 {
+ fn from(ts: TimeSpan) -> Self {
+ (ts.seconds as f64)
+ + ((ts.nsec as f64) / 1_000_000_000.0)
+ + ((ts.usec as f64) / 1_000_000.0)
+ + ((ts.msec as f64) / 1_000.0)
+ + ((ts.minutes as f64) * 60.0)
+ + ((ts.hours as f64) * 3600.0)
+ + ((ts.days as f64) * 3600.0 * 24.0)
+ + ((ts.weeks as f64) * 3600.0 * 24.0 * 7.0)
+ + ((ts.months as f64) * 3600.0 * 24.0 * 30.44)
+ + ((ts.years as f64) * 3600.0 * 24.0 * 365.25)
+ }
+}
+
+impl From<std::time::Duration> for TimeSpan {
+ fn from(duration: std::time::Duration) -> Self {
+ let mut duration = duration.as_nanos();
+ let nsec = (duration % 1000) as u64;
+ duration /= 1000;
+ let usec = (duration % 1000) as u64;
+ duration /= 1000;
+ let msec = (duration % 1000) as u64;
+ duration /= 1000;
+ let seconds = (duration % 60) as u64;
+ duration /= 60;
+ let minutes = (duration % 60) as u64;
+ duration /= 60;
+ let hours = (duration % 24) as u64;
+ duration /= 24;
+ let years = (duration as f64 / 365.25) as u64;
+ let ydays = (duration as f64 % 365.25) as u64;
+ let months = (ydays as f64 / 30.44) as u64;
+ let mdays = (ydays as f64 % 30.44) as u64;
+ let weeks = mdays / 7;
+ let days = mdays % 7;
+ Self {
+ nsec,
+ usec,
+ msec,
+ seconds,
+ minutes,
+ hours,
+ days,
+ weeks,
+ months,
+ years,
+ }
+ }
+}
+
+impl std::fmt::Display for TimeSpan {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ let mut first = true;
+ {
+ // block scope for mutable borrows
+ let mut do_write = |v: u64, unit: &str| -> Result<(), std::fmt::Error> {
+ if !first {
+ write!(f, " ")?;
+ }
+ first = false;
+ write!(f, "{}{}", v, unit)
+ };
+ if self.years > 0 {
+ do_write(self.years, "y")?;
+ }
+ if self.months > 0 {
+ do_write(self.months, "m")?;
+ }
+ if self.weeks > 0 {
+ do_write(self.weeks, "w")?;
+ }
+ if self.days > 0 {
+ do_write(self.days, "d")?;
+ }
+ if self.hours > 0 {
+ do_write(self.hours, "h")?;
+ }
+ if self.minutes > 0 {
+ do_write(self.minutes, "min")?;
+ }
+ }
+ if !first {
+ write!(f, " ")?;
+ }
+ let seconds = self.seconds as f64 + (self.msec as f64 / 1000.0);
+ if seconds >= 0.1 {
+ if seconds >= 1.0 || !first {
+ write!(f, "{:.0}s", seconds)?;
+ } else {
+ write!(f, "{:.1}s", seconds)?;
+ }
+ } else if first {
+ write!(f, "<0.1s")?;
+ }
+ Ok(())
+ }
+}
+
+fn parse_time_unit(i: &str) -> IResult<&str, &str> {
+ let (n, text) = take_while1(|c: char| char::is_ascii_alphabetic(&c) || c == 'µ')(i)?;
+ if TIME_SPAN_UNITS.contains_key(&text) {
+ Ok((n, text))
+ } else {
+ Err(parse_error(text, "time unit"))
+ }
+}
+
+/// Parse a [TimeSpan]
+pub fn parse_time_span(i: &str) -> Result<TimeSpan, Error> {
+ parse_complete_line("time span", i, parse_time_span_incomplete)
+}
+
+fn parse_time_span_incomplete(mut i: &str) -> IResult<&str, TimeSpan> {
+ let mut ts = TimeSpan::default();
+
+ loop {
+ i = space0(i)?.0;
+ if i.is_empty() {
+ break;
+ }
+ let (n, num) = parse_u64(i)?;
+ i = space0(n)?.0;
+
+ if let (n, Some(unit)) = opt(parse_time_unit)(i)? {
+ i = n;
+ match unit {
+ "seconds" | "second" | "sec" | "s" => {
+ ts.seconds += num;
+ }
+ "msec" | "ms" => {
+ ts.msec += num;
+ }
+ "usec" | "us" | "µs" => {
+ ts.usec += num;
+ }
+ "nsec" | "ns" => {
+ ts.nsec += num;
+ }
+ "minutes" | "minute" | "min" | "m" => {
+ ts.minutes += num;
+ }
+ "hours" | "hour" | "hr" | "h" => {
+ ts.hours += num;
+ }
+ "days" | "day" | "d" => {
+ ts.days += num;
+ }
+ "weeks" | "week" | "w" => {
+ ts.weeks += num;
+ }
+ "months" | "month" | "M" => {
+ ts.months += num;
+ }
+ "years" | "year" | "y" => {
+ ts.years += num;
+ }
+ _ => return Err(parse_error(unit, "internal error")),
+ }
+ } else {
+ ts.seconds += num;
+ }
+ }
+
+ Ok((i, ts))
+}
+
+/// Verify the format of the [TimeSpan]
+pub fn verify_time_span(i: &str) -> Result<(), Error> {
+ parse_time_span(i)?;
+ Ok(())
+}
+
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 10/14] proxmox-time: move tests from time.rs to test.rs
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (8 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 09/14] proxmox-time: move TimeSpan into time_span.rs Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 11/14] proxmox-time: lib.rs: rustfmt Dominik Csapak
` (5 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/lib.rs | 6 +-
proxmox-time/src/test.rs | 263 +++++++++++++++++++++++++++++++++++++++
proxmox-time/src/time.rs | 231 ----------------------------------
3 files changed, 266 insertions(+), 234 deletions(-)
create mode 100644 proxmox-time/src/test.rs
delete mode 100644 proxmox-time/src/time.rs
diff --git a/proxmox-time/src/lib.rs b/proxmox-time/src/lib.rs
index cbb7008..fa59eee 100644
--- a/proxmox-time/src/lib.rs
+++ b/proxmox-time/src/lib.rs
@@ -7,9 +7,6 @@ use anyhow::{bail, format_err, Error};
mod tm_editor;
pub use tm_editor::*;
-mod time;
-pub use time::*;
-
pub(crate) mod parse_helpers;
pub(crate) mod date_time_value;
@@ -26,6 +23,9 @@ pub use week_days::*;
mod daily_duration;
pub use daily_duration::*;
+#[cfg(test)]
+mod test;
+
/// Safe bindings to libc timelocal
///
/// We set tm_isdst to -1.
diff --git a/proxmox-time/src/test.rs b/proxmox-time/src/test.rs
new file mode 100644
index 0000000..3007156
--- /dev/null
+++ b/proxmox-time/src/test.rs
@@ -0,0 +1,263 @@
+use anyhow::bail;
+
+use super::*;
+
+fn test_event(v: &'static str) -> Result<(), Error> {
+ match parse_calendar_event(v) {
+ Ok(event) => println!("CalendarEvent '{}' => {:?}", v, event),
+ Err(err) => bail!("parsing '{}' failed - {}", v, err),
+ }
+
+ Ok(())
+}
+
+const fn make_test_time(mday: i32, hour: i32, min: i32) -> i64 {
+ (mday * 3600 * 24 + hour * 3600 + min * 60) as i64
+}
+
+#[test]
+fn test_compute_next_event() -> Result<(), Error> {
+ let test_value = |v: &'static str, last: i64, expect: i64| -> Result<i64, Error> {
+ let event = match parse_calendar_event(v) {
+ Ok(event) => event,
+ Err(err) => bail!("parsing '{}' failed - {}", v, err),
+ };
+
+ match compute_next_event(&event, last, true) {
+ Ok(Some(next)) => {
+ if next == expect {
+ println!("next {:?} => {}", event, next);
+ } else {
+ bail!(
+ "next {:?} failed\nnext: {:?}\nexpect: {:?}",
+ event,
+ crate::gmtime(next),
+ crate::gmtime(expect),
+ );
+ }
+ }
+ Ok(None) => bail!("next {:?} failed to find a timestamp", event),
+ Err(err) => bail!("compute next for '{}' failed - {}", v, err),
+ }
+
+ Ok(expect)
+ };
+
+ let test_never = |v: &'static str, last: i64| -> Result<(), Error> {
+ let event = match parse_calendar_event(v) {
+ Ok(event) => event,
+ Err(err) => bail!("parsing '{}' failed - {}", v, err),
+ };
+
+ match compute_next_event(&event, last, true)? {
+ None => Ok(()),
+ Some(next) => bail!(
+ "compute next for '{}' succeeded, but expected fail - result {}",
+ v,
+ next
+ ),
+ }
+ };
+
+ const MIN: i64 = 60;
+ const HOUR: i64 = 3600;
+ const DAY: i64 = 3600 * 24;
+
+ const THURSDAY_00_00: i64 = make_test_time(0, 0, 0);
+ const THURSDAY_15_00: i64 = make_test_time(0, 15, 0);
+
+ const JUL_31_2020: i64 = 1596153600; // Friday, 2020-07-31 00:00:00
+ const DEC_31_2020: i64 = 1609372800; // Thursday, 2020-12-31 00:00:00
+
+ // minute only syntax
+ test_value("0", THURSDAY_00_00, THURSDAY_00_00 + HOUR)?;
+ test_value("*", THURSDAY_00_00, THURSDAY_00_00 + MIN)?;
+
+ test_value("*:0", THURSDAY_00_00, THURSDAY_00_00 + HOUR)?;
+ test_value("*:*", THURSDAY_00_00, THURSDAY_00_00 + MIN)?;
+ test_value("*:*:*", THURSDAY_00_00, THURSDAY_00_00 + 1)?;
+ test_value("*:3:5", THURSDAY_00_00, THURSDAY_00_00 + 3 * MIN + 5)?;
+
+ test_value("mon *:*", THURSDAY_00_00, THURSDAY_00_00 + 4 * DAY)?;
+ test_value(
+ "mon 2:*",
+ THURSDAY_00_00,
+ THURSDAY_00_00 + 4 * DAY + 2 * HOUR,
+ )?;
+ test_value(
+ "mon 2:50",
+ THURSDAY_00_00,
+ THURSDAY_00_00 + 4 * DAY + 2 * HOUR + 50 * MIN,
+ )?;
+
+ test_value("tue", THURSDAY_00_00, THURSDAY_00_00 + 5 * DAY)?;
+ test_value("wed", THURSDAY_00_00, THURSDAY_00_00 + 6 * DAY)?;
+ test_value("thu", THURSDAY_00_00, THURSDAY_00_00 + 7 * DAY)?;
+ test_value("fri", THURSDAY_00_00, THURSDAY_00_00 + 1 * DAY)?;
+ test_value("sat", THURSDAY_00_00, THURSDAY_00_00 + 2 * DAY)?;
+ test_value("sun", THURSDAY_00_00, THURSDAY_00_00 + 3 * DAY)?;
+
+ // test repeated ranges
+ test_value("4..10/2:0", THURSDAY_00_00, THURSDAY_00_00 + 4 * HOUR)?;
+ test_value(
+ "4..10/2:0",
+ THURSDAY_00_00 + 5 * HOUR,
+ THURSDAY_00_00 + 6 * HOUR,
+ )?;
+ test_value(
+ "4..10/2:0",
+ THURSDAY_00_00 + 11 * HOUR,
+ THURSDAY_00_00 + 1 * DAY + 4 * HOUR,
+ )?;
+
+ // test multiple values for a single field
+ // and test that the order does not matter
+ test_value(
+ "5,10:4,8",
+ THURSDAY_00_00,
+ THURSDAY_00_00 + 5 * HOUR + 4 * MIN,
+ )?;
+ test_value(
+ "10,5:8,4",
+ THURSDAY_00_00,
+ THURSDAY_00_00 + 5 * HOUR + 4 * MIN,
+ )?;
+ test_value(
+ "6,4..10:23,5/5",
+ THURSDAY_00_00,
+ THURSDAY_00_00 + 4 * HOUR + 5 * MIN,
+ )?;
+ test_value(
+ "4..10,6:5/5,23",
+ THURSDAY_00_00,
+ THURSDAY_00_00 + 4 * HOUR + 5 * MIN,
+ )?;
+
+ // test month wrapping
+ test_value("sat", JUL_31_2020, JUL_31_2020 + 1 * DAY)?;
+ test_value("sun", JUL_31_2020, JUL_31_2020 + 2 * DAY)?;
+ test_value("mon", JUL_31_2020, JUL_31_2020 + 3 * DAY)?;
+ test_value("tue", JUL_31_2020, JUL_31_2020 + 4 * DAY)?;
+ test_value("wed", JUL_31_2020, JUL_31_2020 + 5 * DAY)?;
+ test_value("thu", JUL_31_2020, JUL_31_2020 + 6 * DAY)?;
+ test_value("fri", JUL_31_2020, JUL_31_2020 + 7 * DAY)?;
+
+ // test year wrapping
+ test_value("fri", DEC_31_2020, DEC_31_2020 + 1 * DAY)?;
+ test_value("sat", DEC_31_2020, DEC_31_2020 + 2 * DAY)?;
+ test_value("sun", DEC_31_2020, DEC_31_2020 + 3 * DAY)?;
+ test_value("mon", DEC_31_2020, DEC_31_2020 + 4 * DAY)?;
+ test_value("tue", DEC_31_2020, DEC_31_2020 + 5 * DAY)?;
+ test_value("wed", DEC_31_2020, DEC_31_2020 + 6 * DAY)?;
+ test_value("thu", DEC_31_2020, DEC_31_2020 + 7 * DAY)?;
+
+ test_value("daily", THURSDAY_00_00, THURSDAY_00_00 + DAY)?;
+ test_value("daily", THURSDAY_00_00 + 1, THURSDAY_00_00 + DAY)?;
+
+ let n = test_value("5/2:0", THURSDAY_00_00, THURSDAY_00_00 + 5 * HOUR)?;
+ let n = test_value("5/2:0", n, THURSDAY_00_00 + 7 * HOUR)?;
+ let n = test_value("5/2:0", n, THURSDAY_00_00 + 9 * HOUR)?;
+ test_value("5/2:0", n, THURSDAY_00_00 + 11 * HOUR)?;
+
+ let mut n = test_value("*:*", THURSDAY_00_00, THURSDAY_00_00 + MIN)?;
+ for i in 2..100 {
+ n = test_value("*:*", n, THURSDAY_00_00 + i * MIN)?;
+ }
+
+ let mut n = test_value("*:0", THURSDAY_00_00, THURSDAY_00_00 + HOUR)?;
+ for i in 2..100 {
+ n = test_value("*:0", n, THURSDAY_00_00 + i * HOUR)?;
+ }
+
+ let mut n = test_value("1:0", THURSDAY_15_00, THURSDAY_00_00 + DAY + HOUR)?;
+ for i in 2..100 {
+ n = test_value("1:0", n, THURSDAY_00_00 + i * DAY + HOUR)?;
+ }
+
+ // test date functionality
+
+ test_value("2020-07-31", 0, JUL_31_2020)?;
+ test_value("02-28", 0, (31 + 27) * DAY)?;
+ test_value("02-29", 0, 2 * 365 * DAY + (31 + 28) * DAY)?; // 1972-02-29
+ test_value("1965/5-01-01", -1, THURSDAY_00_00)?;
+ test_value("2020-7..9-2/2", JUL_31_2020, JUL_31_2020 + 2 * DAY)?;
+ test_value("2020,2021-12-31", JUL_31_2020, DEC_31_2020)?;
+
+ test_value("monthly", 0, 31 * DAY)?;
+ test_value("quarterly", 0, (31 + 28 + 31) * DAY)?;
+ test_value("semiannually", 0, (31 + 28 + 31 + 30 + 31 + 30) * DAY)?;
+ test_value("yearly", 0, (365) * DAY)?;
+
+ test_never("2021-02-29", 0)?;
+ test_never("02-30", 0)?;
+
+ Ok(())
+}
+
+#[test]
+fn test_calendar_event_weekday() -> Result<(), Error> {
+ test_event("mon,wed..fri")?;
+ test_event("fri..mon")?;
+
+ test_event("mon")?;
+ test_event("MON")?;
+ test_event("monDay")?;
+ test_event("tue")?;
+ test_event("Tuesday")?;
+ test_event("wed")?;
+ test_event("wednesday")?;
+ test_event("thu")?;
+ test_event("thursday")?;
+ test_event("fri")?;
+ test_event("friday")?;
+ test_event("sat")?;
+ test_event("saturday")?;
+ test_event("sun")?;
+ test_event("sunday")?;
+
+ test_event("mon..fri")?;
+ test_event("mon,tue,fri")?;
+ test_event("mon,tue..wednesday,fri..sat")?;
+
+ Ok(())
+}
+
+#[test]
+fn test_time_span_parser() -> Result<(), Error> {
+ let test_value = |ts_str: &str, expect: f64| -> Result<(), Error> {
+ let ts = parse_time_span(ts_str)?;
+ assert_eq!(f64::from(ts), expect, "{}", ts_str);
+ Ok(())
+ };
+
+ test_value("2", 2.0)?;
+ test_value("2s", 2.0)?;
+ test_value("2sec", 2.0)?;
+ test_value("2second", 2.0)?;
+ test_value("2seconds", 2.0)?;
+
+ test_value(" 2s 2 s 2", 6.0)?;
+
+ test_value("1msec 1ms", 0.002)?;
+ test_value("1usec 1us 1µs", 0.000_003)?;
+ test_value("1nsec 1ns", 0.000_000_002)?;
+ test_value("1minutes 1minute 1min 1m", 4.0 * 60.0)?;
+ test_value("1hours 1hour 1hr 1h", 4.0 * 3600.0)?;
+ test_value("1days 1day 1d", 3.0 * 86400.0)?;
+ test_value("1weeks 1 week 1w", 3.0 * 86400.0 * 7.0)?;
+ test_value("1months 1month 1M", 3.0 * 86400.0 * 30.44)?;
+ test_value("1years 1year 1y", 3.0 * 86400.0 * 365.25)?;
+
+ test_value("2h", 7200.0)?;
+ test_value(" 2 h", 7200.0)?;
+ test_value("2hours", 7200.0)?;
+ test_value("48hr", 48.0 * 3600.0)?;
+ test_value(
+ "1y 12month",
+ 365.25 * 24.0 * 3600.0 + 12.0 * 30.44 * 24.0 * 3600.0,
+ )?;
+ test_value("55s500ms", 55.5)?;
+ test_value("300ms20s 5day", 5.0 * 24.0 * 3600.0 + 20.0 + 0.3)?;
+
+ Ok(())
+}
diff --git a/proxmox-time/src/time.rs b/proxmox-time/src/time.rs
deleted file mode 100644
index ac2f510..0000000
--- a/proxmox-time/src/time.rs
+++ /dev/null
@@ -1,231 +0,0 @@
-#[cfg(test)]
-mod test {
-
- use anyhow::bail;
- use crate::*;
-
-
- fn test_event(v: &'static str) -> Result<(), Error> {
- match parse_calendar_event(v) {
- Ok(event) => println!("CalendarEvent '{}' => {:?}", v, event),
- Err(err) => bail!("parsing '{}' failed - {}", v, err),
- }
-
- Ok(())
- }
-
- const fn make_test_time(mday: i32, hour: i32, min: i32) -> i64 {
- (mday*3600*24 + hour*3600 + min*60) as i64
- }
-
- #[test]
- #[allow(clippy::identity_op)]
- fn test_compute_next_event() -> Result<(), Error> {
-
- let test_value = |v: &'static str, last: i64, expect: i64| -> Result<i64, Error> {
- let event = match parse_calendar_event(v) {
- Ok(event) => event,
- Err(err) => bail!("parsing '{}' failed - {}", v, err),
- };
-
- match compute_next_event(&event, last, true) {
- Ok(Some(next)) => {
- if next == expect {
- println!("next {:?} => {}", event, next);
- } else {
- bail!(
- "next {:?} failed\nnext: {:?}\nexpect: {:?}",
- event,
- crate::gmtime(next),
- crate::gmtime(expect),
- );
- }
- }
- Ok(None) => bail!("next {:?} failed to find a timestamp", event),
- Err(err) => bail!("compute next for '{}' failed - {}", v, err),
- }
-
- Ok(expect)
- };
-
- let test_never = |v: &'static str, last: i64| -> Result<(), Error> {
- let event = match parse_calendar_event(v) {
- Ok(event) => event,
- Err(err) => bail!("parsing '{}' failed - {}", v, err),
- };
-
- match compute_next_event(&event, last, true)? {
- None => Ok(()),
- Some(next) => bail!("compute next for '{}' succeeded, but expected fail - result {}", v, next),
- }
- };
-
- const MIN: i64 = 60;
- const HOUR: i64 = 3600;
- const DAY: i64 = 3600*24;
-
- const THURSDAY_00_00: i64 = make_test_time(0, 0, 0);
- const THURSDAY_15_00: i64 = make_test_time(0, 15, 0);
-
- const JUL_31_2020: i64 = 1596153600; // Friday, 2020-07-31 00:00:00
- const DEC_31_2020: i64 = 1609372800; // Thursday, 2020-12-31 00:00:00
-
- // minute only syntax
- test_value("0", THURSDAY_00_00, THURSDAY_00_00 + HOUR)?;
- test_value("*", THURSDAY_00_00, THURSDAY_00_00 + MIN)?;
-
- test_value("*:0", THURSDAY_00_00, THURSDAY_00_00 + HOUR)?;
- test_value("*:*", THURSDAY_00_00, THURSDAY_00_00 + MIN)?;
- test_value("*:*:*", THURSDAY_00_00, THURSDAY_00_00 + 1)?;
- test_value("*:3:5", THURSDAY_00_00, THURSDAY_00_00 + 3*MIN + 5)?;
-
- test_value("mon *:*", THURSDAY_00_00, THURSDAY_00_00 + 4*DAY)?;
- test_value("mon 2:*", THURSDAY_00_00, THURSDAY_00_00 + 4*DAY + 2*HOUR)?;
- test_value("mon 2:50", THURSDAY_00_00, THURSDAY_00_00 + 4*DAY + 2*HOUR + 50*MIN)?;
-
- test_value("tue", THURSDAY_00_00, THURSDAY_00_00 + 5*DAY)?;
- test_value("wed", THURSDAY_00_00, THURSDAY_00_00 + 6*DAY)?;
- test_value("thu", THURSDAY_00_00, THURSDAY_00_00 + 7*DAY)?;
- test_value("fri", THURSDAY_00_00, THURSDAY_00_00 + 1*DAY)?;
- test_value("sat", THURSDAY_00_00, THURSDAY_00_00 + 2*DAY)?;
- test_value("sun", THURSDAY_00_00, THURSDAY_00_00 + 3*DAY)?;
-
- // test repeated ranges
- test_value("4..10/2:0", THURSDAY_00_00, THURSDAY_00_00 + 4*HOUR)?;
- test_value("4..10/2:0", THURSDAY_00_00 + 5*HOUR, THURSDAY_00_00 + 6*HOUR)?;
- test_value("4..10/2:0", THURSDAY_00_00 + 11*HOUR, THURSDAY_00_00 + 1*DAY + 4*HOUR)?;
-
- // test multiple values for a single field
- // and test that the order does not matter
- test_value("5,10:4,8", THURSDAY_00_00, THURSDAY_00_00 + 5*HOUR + 4*MIN)?;
- test_value("10,5:8,4", THURSDAY_00_00, THURSDAY_00_00 + 5*HOUR + 4*MIN)?;
- test_value("6,4..10:23,5/5", THURSDAY_00_00, THURSDAY_00_00 + 4*HOUR + 5*MIN)?;
- test_value("4..10,6:5/5,23", THURSDAY_00_00, THURSDAY_00_00 + 4*HOUR + 5*MIN)?;
-
- // test month wrapping
- test_value("sat", JUL_31_2020, JUL_31_2020 + 1*DAY)?;
- test_value("sun", JUL_31_2020, JUL_31_2020 + 2*DAY)?;
- test_value("mon", JUL_31_2020, JUL_31_2020 + 3*DAY)?;
- test_value("tue", JUL_31_2020, JUL_31_2020 + 4*DAY)?;
- test_value("wed", JUL_31_2020, JUL_31_2020 + 5*DAY)?;
- test_value("thu", JUL_31_2020, JUL_31_2020 + 6*DAY)?;
- test_value("fri", JUL_31_2020, JUL_31_2020 + 7*DAY)?;
-
- // test year wrapping
- test_value("fri", DEC_31_2020, DEC_31_2020 + 1*DAY)?;
- test_value("sat", DEC_31_2020, DEC_31_2020 + 2*DAY)?;
- test_value("sun", DEC_31_2020, DEC_31_2020 + 3*DAY)?;
- test_value("mon", DEC_31_2020, DEC_31_2020 + 4*DAY)?;
- test_value("tue", DEC_31_2020, DEC_31_2020 + 5*DAY)?;
- test_value("wed", DEC_31_2020, DEC_31_2020 + 6*DAY)?;
- test_value("thu", DEC_31_2020, DEC_31_2020 + 7*DAY)?;
-
- test_value("daily", THURSDAY_00_00, THURSDAY_00_00 + DAY)?;
- test_value("daily", THURSDAY_00_00+1, THURSDAY_00_00 + DAY)?;
-
- let n = test_value("5/2:0", THURSDAY_00_00, THURSDAY_00_00 + 5*HOUR)?;
- let n = test_value("5/2:0", n, THURSDAY_00_00 + 7*HOUR)?;
- let n = test_value("5/2:0", n, THURSDAY_00_00 + 9*HOUR)?;
- test_value("5/2:0", n, THURSDAY_00_00 + 11*HOUR)?;
-
- let mut n = test_value("*:*", THURSDAY_00_00, THURSDAY_00_00 + MIN)?;
- for i in 2..100 {
- n = test_value("*:*", n, THURSDAY_00_00 + i*MIN)?;
- }
-
- let mut n = test_value("*:0", THURSDAY_00_00, THURSDAY_00_00 + HOUR)?;
- for i in 2..100 {
- n = test_value("*:0", n, THURSDAY_00_00 + i*HOUR)?;
- }
-
- let mut n = test_value("1:0", THURSDAY_15_00, THURSDAY_00_00 + DAY + HOUR)?;
- for i in 2..100 {
- n = test_value("1:0", n, THURSDAY_00_00 + i*DAY + HOUR)?;
- }
-
- // test date functionality
-
- test_value("2020-07-31", 0, JUL_31_2020)?;
- test_value("02-28", 0, (31+27)*DAY)?;
- test_value("02-29", 0, 2*365*DAY + (31+28)*DAY)?; // 1972-02-29
- test_value("1965/5-01-01", -1, THURSDAY_00_00)?;
- test_value("2020-7..9-2/2", JUL_31_2020, JUL_31_2020 + 2*DAY)?;
- test_value("2020,2021-12-31", JUL_31_2020, DEC_31_2020)?;
-
- test_value("monthly", 0, 31*DAY)?;
- test_value("quarterly", 0, (31+28+31)*DAY)?;
- test_value("semiannually", 0, (31+28+31+30+31+30)*DAY)?;
- test_value("yearly", 0, (365)*DAY)?;
-
- test_never("2021-02-29", 0)?;
- test_never("02-30", 0)?;
-
- Ok(())
- }
-
- #[test]
- fn test_calendar_event_weekday() -> Result<(), Error> {
- test_event("mon,wed..fri")?;
- test_event("fri..mon")?;
-
- test_event("mon")?;
- test_event("MON")?;
- test_event("monDay")?;
- test_event("tue")?;
- test_event("Tuesday")?;
- test_event("wed")?;
- test_event("wednesday")?;
- test_event("thu")?;
- test_event("thursday")?;
- test_event("fri")?;
- test_event("friday")?;
- test_event("sat")?;
- test_event("saturday")?;
- test_event("sun")?;
- test_event("sunday")?;
-
- test_event("mon..fri")?;
- test_event("mon,tue,fri")?;
- test_event("mon,tue..wednesday,fri..sat")?;
-
- Ok(())
- }
-
- #[test]
- fn test_time_span_parser() -> Result<(), Error> {
-
- let test_value = |ts_str: &str, expect: f64| -> Result<(), Error> {
- let ts = parse_time_span(ts_str)?;
- assert_eq!(f64::from(ts), expect, "{}", ts_str);
- Ok(())
- };
-
- test_value("2", 2.0)?;
- test_value("2s", 2.0)?;
- test_value("2sec", 2.0)?;
- test_value("2second", 2.0)?;
- test_value("2seconds", 2.0)?;
-
- test_value(" 2s 2 s 2", 6.0)?;
-
- test_value("1msec 1ms", 0.002)?;
- test_value("1usec 1us 1µs", 0.000_003)?;
- test_value("1nsec 1ns", 0.000_000_002)?;
- test_value("1minutes 1minute 1min 1m", 4.0*60.0)?;
- test_value("1hours 1hour 1hr 1h", 4.0*3600.0)?;
- test_value("1days 1day 1d", 3.0*86400.0)?;
- test_value("1weeks 1 week 1w", 3.0*86400.0*7.0)?;
- test_value("1months 1month 1M", 3.0*86400.0*30.44)?;
- test_value("1years 1year 1y", 3.0*86400.0*365.25)?;
-
- test_value("2h", 7200.0)?;
- test_value(" 2 h", 7200.0)?;
- test_value("2hours", 7200.0)?;
- test_value("48hr", 48.0*3600.0)?;
- test_value("1y 12month", 365.25*24.0*3600.0 + 12.0*30.44*24.0*3600.0)?;
- test_value("55s500ms", 55.5)?;
- test_value("300ms20s 5day", 5.0*24.0*3600.0 + 20.0 + 0.3)?;
-
- Ok(())
- }
-}
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 11/14] proxmox-time: lib.rs: rustfmt
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (9 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 10/14] proxmox-time: move tests from time.rs to test.rs Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 12/14] proxmox-time: calendar-events: make compute_next_event a method Dominik Csapak
` (4 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/lib.rs | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/proxmox-time/src/lib.rs b/proxmox-time/src/lib.rs
index fa59eee..53ba11e 100644
--- a/proxmox-time/src/lib.rs
+++ b/proxmox-time/src/lib.rs
@@ -145,8 +145,7 @@ extern "C" {
/// Safe bindings to libc strftime
pub fn strftime(format: &str, t: &libc::tm) -> Result<String, Error> {
- let format = CString::new(format)
- .map_err(|err| format_err!("{}", err))?;
+ let format = CString::new(format).map_err(|err| format_err!("{}", err))?;
let mut buf = vec![0u8; 8192];
let res = unsafe {
@@ -157,7 +156,8 @@ pub fn strftime(format: &str, t: &libc::tm) -> Result<String, Error> {
t as *const libc::tm,
)
};
- if res == !0 { // -1,, it's unsigned
+ if res == !0 {
+ // -1,, it's unsigned
bail!("strftime failed");
}
let len = res as usize;
@@ -166,8 +166,7 @@ pub fn strftime(format: &str, t: &libc::tm) -> Result<String, Error> {
bail!("strftime: result len is 0 (string too large)");
};
- let c_str = CStr::from_bytes_with_nul(&buf[..len + 1])
- .map_err(|err| format_err!("{}", err))?;
+ let c_str = CStr::from_bytes_with_nul(&buf[..len + 1]).map_err(|err| format_err!("{}", err))?;
let str_slice: &str = c_str.to_str().unwrap();
Ok(str_slice.to_owned())
}
@@ -229,10 +228,13 @@ pub fn epoch_to_rfc3339(epoch: i64) -> Result<String, Error> {
/// Parse RFC3339 into Unix epoch
pub fn parse_rfc3339(input_str: &str) -> Result<i64, Error> {
- parse_rfc3339_do(input_str)
- .map_err(|err| {
- format_err!("failed to parse rfc3339 timestamp ({:?}) - {}", input_str, err)
- })
+ parse_rfc3339_do(input_str).map_err(|err| {
+ format_err!(
+ "failed to parse rfc3339 timestamp ({:?}) - {}",
+ input_str,
+ err
+ )
+ })
}
fn parse_rfc3339_do(input_str: &str) -> Result<i64, Error> {
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 12/14] proxmox-time: calendar-events: make compute_next_event a method
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (10 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 11/14] proxmox-time: lib.rs: rustfmt Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 13/14] proxmox-time: calendar_events: implement FromStr Dominik Csapak
` (3 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
and deprecated the standalone function
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/calendar_event.rs | 221 +++++++++++++++--------------
proxmox-time/src/test.rs | 4 +-
2 files changed, 117 insertions(+), 108 deletions(-)
diff --git a/proxmox-time/src/calendar_event.rs b/proxmox-time/src/calendar_event.rs
index 1c21a84..a839f9d 100644
--- a/proxmox-time/src/calendar_event.rs
+++ b/proxmox-time/src/calendar_event.rs
@@ -35,141 +35,150 @@ pub struct CalendarEvent {
pub(crate) year: Vec<DateTimeValue>,
}
-/// Verify the format of the [CalendarEvent]
-pub fn verify_calendar_event(i: &str) -> Result<(), Error> {
- parse_calendar_event(i)?;
- Ok(())
-}
-
-/// Compute the next event
-pub fn compute_next_event(
- event: &CalendarEvent,
- last: i64,
- utc: bool,
-) -> Result<Option<i64>, Error> {
+impl CalendarEvent {
+ /// Computes the next timestamp after `last`. If `utc` is false, the local
+ /// timezone will be used for the calculation.
+ pub fn compute_next_event(&self, last: i64, utc: bool) -> Result<Option<i64>, Error> {
+ let last = last + 1; // at least one second later
- let last = last + 1; // at least one second later
+ let all_days = self.days.is_empty() || self.days.is_all();
- let all_days = event.days.is_empty() || event.days.is_all();
+ let mut t = TmEditor::with_epoch(last, utc)?;
- let mut t = TmEditor::with_epoch(last, utc)?;
+ let mut count = 0;
- let mut count = 0;
-
- loop {
- // cancel after 1000 loops
- if count > 1000 {
- return Ok(None);
- } else {
- count += 1;
- }
+ loop {
+ // cancel after 1000 loops
+ if count > 1000 {
+ return Ok(None);
+ } else {
+ count += 1;
+ }
- if !event.year.is_empty() {
- let year: u32 = t.year().try_into()?;
- if !DateTimeValue::list_contains(&event.year, year) {
- if let Some(n) = DateTimeValue::find_next(&event.year, year) {
- t.add_years((n - year).try_into()?)?;
- continue;
- } else {
- // if we have no valid year, we cannot find a correct timestamp
- return Ok(None);
+ if !self.year.is_empty() {
+ let year: u32 = t.year().try_into()?;
+ if !DateTimeValue::list_contains(&self.year, year) {
+ if let Some(n) = DateTimeValue::find_next(&self.year, year) {
+ t.add_years((n - year).try_into()?)?;
+ continue;
+ } else {
+ // if we have no valid year, we cannot find a correct timestamp
+ return Ok(None);
+ }
}
}
- }
- if !event.month.is_empty() {
- let month: u32 = t.month().try_into()?;
- if !DateTimeValue::list_contains(&event.month, month) {
- if let Some(n) = DateTimeValue::find_next(&event.month, month) {
- t.add_months((n - month).try_into()?)?;
- } else {
- // if we could not find valid month, retry next year
- t.add_years(1)?;
+ if !self.month.is_empty() {
+ let month: u32 = t.month().try_into()?;
+ if !DateTimeValue::list_contains(&self.month, month) {
+ if let Some(n) = DateTimeValue::find_next(&self.month, month) {
+ t.add_months((n - month).try_into()?)?;
+ } else {
+ // if we could not find valid month, retry next year
+ t.add_years(1)?;
+ }
+ continue;
}
- continue;
}
- }
- if !event.day.is_empty() {
- let day: u32 = t.day().try_into()?;
- if !DateTimeValue::list_contains(&event.day, day) {
- if let Some(n) = DateTimeValue::find_next(&event.day, day) {
- t.add_days((n - day).try_into()?)?;
- } else {
- // if we could not find valid mday, retry next month
- t.add_months(1)?;
+ if !self.day.is_empty() {
+ let day: u32 = t.day().try_into()?;
+ if !DateTimeValue::list_contains(&self.day, day) {
+ if let Some(n) = DateTimeValue::find_next(&self.day, day) {
+ t.add_days((n - day).try_into()?)?;
+ } else {
+ // if we could not find valid mday, retry next month
+ t.add_months(1)?;
+ }
+ continue;
}
- continue;
}
- }
- if !all_days { // match day first
- let day_num: u32 = t.day_num().try_into()?;
- let day = WeekDays::from_bits(1<<day_num).unwrap();
- if !event.days.contains(day) {
- if let Some(n) = ((day_num+1)..7)
- .find(|d| event.days.contains(WeekDays::from_bits(1<<d).unwrap()))
- {
- // try next day
- t.add_days((n - day_num).try_into()?)?;
- } else {
- // try next week
- t.add_days((7 - day_num).try_into()?)?;
+ if !all_days {
+ // match day first
+ let day_num: u32 = t.day_num().try_into()?;
+ let day = WeekDays::from_bits(1 << day_num).unwrap();
+ if !self.days.contains(day) {
+ if let Some(n) = ((day_num + 1)..7)
+ .find(|d| self.days.contains(WeekDays::from_bits(1 << d).unwrap()))
+ {
+ // try next day
+ t.add_days((n - day_num).try_into()?)?;
+ } else {
+ // try next week
+ t.add_days((7 - day_num).try_into()?)?;
+ }
+ continue;
}
- continue;
}
- }
- // this day
- if !event.hour.is_empty() {
- let hour = t.hour().try_into()?;
- if !DateTimeValue::list_contains(&event.hour, hour) {
- if let Some(n) = DateTimeValue::find_next(&event.hour, hour) {
- // test next hour
- t.set_time(n.try_into()?, 0, 0)?;
- } else {
- // test next day
- t.add_days(1)?;
+ // this day
+ if !self.hour.is_empty() {
+ let hour = t.hour().try_into()?;
+ if !DateTimeValue::list_contains(&self.hour, hour) {
+ if let Some(n) = DateTimeValue::find_next(&self.hour, hour) {
+ // test next hour
+ t.set_time(n.try_into()?, 0, 0)?;
+ } else {
+ // test next day
+ t.add_days(1)?;
+ }
+ continue;
}
- continue;
}
- }
- // this hour
- if !event.minute.is_empty() {
- let minute = t.min().try_into()?;
- if !DateTimeValue::list_contains(&event.minute, minute) {
- if let Some(n) = DateTimeValue::find_next(&event.minute, minute) {
- // test next minute
- t.set_min_sec(n.try_into()?, 0)?;
- } else {
- // test next hour
- t.set_time(t.hour() + 1, 0, 0)?;
+ // this hour
+ if !self.minute.is_empty() {
+ let minute = t.min().try_into()?;
+ if !DateTimeValue::list_contains(&self.minute, minute) {
+ if let Some(n) = DateTimeValue::find_next(&self.minute, minute) {
+ // test next minute
+ t.set_min_sec(n.try_into()?, 0)?;
+ } else {
+ // test next hour
+ t.set_time(t.hour() + 1, 0, 0)?;
+ }
+ continue;
}
- continue;
}
- }
- // this minute
- if !event.second.is_empty() {
- let second = t.sec().try_into()?;
- if !DateTimeValue::list_contains(&event.second, second) {
- if let Some(n) = DateTimeValue::find_next(&event.second, second) {
- // test next second
- t.set_sec(n.try_into()?)?;
- } else {
- // test next min
- t.set_min_sec(t.min() + 1, 0)?;
+ // this minute
+ if !self.second.is_empty() {
+ let second = t.sec().try_into()?;
+ if !DateTimeValue::list_contains(&self.second, second) {
+ if let Some(n) = DateTimeValue::find_next(&self.second, second) {
+ // test next second
+ t.set_sec(n.try_into()?)?;
+ } else {
+ // test next min
+ t.set_min_sec(t.min() + 1, 0)?;
+ }
+ continue;
}
- continue;
}
- }
- let next = t.into_epoch()?;
- return Ok(Some(next))
+ let next = t.into_epoch()?;
+ return Ok(Some(next));
+ }
}
}
+/// Verify the format of the [CalendarEvent]
+pub fn verify_calendar_event(i: &str) -> Result<(), Error> {
+ parse_calendar_event(i)?;
+ Ok(())
+}
+
+/// Compute the next event. Use [CalendarEvent::compute_next_event] instead.
+#[deprecated="use method 'compute_next_event' of CalendarEvent instead"]
+pub fn compute_next_event(
+ event: &CalendarEvent,
+ last: i64,
+ utc: bool,
+) -> Result<Option<i64>, Error> {
+ event.compute_next_event(last, utc)
+}
+
/// Parse a [CalendarEvent]
pub fn parse_calendar_event(i: &str) -> Result<CalendarEvent, Error> {
parse_complete_line("calendar event", i, parse_calendar_event_incomplete)
diff --git a/proxmox-time/src/test.rs b/proxmox-time/src/test.rs
index 3007156..8c5e1cf 100644
--- a/proxmox-time/src/test.rs
+++ b/proxmox-time/src/test.rs
@@ -23,7 +23,7 @@ fn test_compute_next_event() -> Result<(), Error> {
Err(err) => bail!("parsing '{}' failed - {}", v, err),
};
- match compute_next_event(&event, last, true) {
+ match event.compute_next_event(last, true) {
Ok(Some(next)) => {
if next == expect {
println!("next {:?} => {}", event, next);
@@ -49,7 +49,7 @@ fn test_compute_next_event() -> Result<(), Error> {
Err(err) => bail!("parsing '{}' failed - {}", v, err),
};
- match compute_next_event(&event, last, true)? {
+ match event.compute_next_event(last, true)? {
None => Ok(()),
Some(next) => bail!(
"compute next for '{}' succeeded, but expected fail - result {}",
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 13/14] proxmox-time: calendar_events: implement FromStr
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (11 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 12/14] proxmox-time: calendar-events: make compute_next_event a method Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 14/14] proxmox-time: time-span: " Dominik Csapak
` (2 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
and deprecate 'parse_calendar_event'
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/calendar_event.rs | 13 +++++++++++--
proxmox-time/src/test.rs | 6 +++---
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/proxmox-time/src/calendar_event.rs b/proxmox-time/src/calendar_event.rs
index a839f9d..d1d74a2 100644
--- a/proxmox-time/src/calendar_event.rs
+++ b/proxmox-time/src/calendar_event.rs
@@ -163,9 +163,17 @@ impl CalendarEvent {
}
}
+impl std::str::FromStr for CalendarEvent {
+ type Err = Error;
+
+ fn from_str(i: &str) -> Result<Self, Self::Err> {
+ parse_complete_line("calendar event", i, parse_calendar_event_incomplete)
+ }
+}
+
/// Verify the format of the [CalendarEvent]
pub fn verify_calendar_event(i: &str) -> Result<(), Error> {
- parse_calendar_event(i)?;
+ let _: CalendarEvent = i.parse()?;
Ok(())
}
@@ -180,8 +188,9 @@ pub fn compute_next_event(
}
/// Parse a [CalendarEvent]
+#[deprecated="use std::str::FromStr trait instead"]
pub fn parse_calendar_event(i: &str) -> Result<CalendarEvent, Error> {
- parse_complete_line("calendar event", i, parse_calendar_event_incomplete)
+ i.parse()
}
fn parse_calendar_event_incomplete(mut i: &str) -> IResult<&str, CalendarEvent> {
diff --git a/proxmox-time/src/test.rs b/proxmox-time/src/test.rs
index 8c5e1cf..0476cc1 100644
--- a/proxmox-time/src/test.rs
+++ b/proxmox-time/src/test.rs
@@ -3,7 +3,7 @@ use anyhow::bail;
use super::*;
fn test_event(v: &'static str) -> Result<(), Error> {
- match parse_calendar_event(v) {
+ match v.parse::<CalendarEvent>() {
Ok(event) => println!("CalendarEvent '{}' => {:?}", v, event),
Err(err) => bail!("parsing '{}' failed - {}", v, err),
}
@@ -18,7 +18,7 @@ const fn make_test_time(mday: i32, hour: i32, min: i32) -> i64 {
#[test]
fn test_compute_next_event() -> Result<(), Error> {
let test_value = |v: &'static str, last: i64, expect: i64| -> Result<i64, Error> {
- let event = match parse_calendar_event(v) {
+ let event: CalendarEvent = match v.parse() {
Ok(event) => event,
Err(err) => bail!("parsing '{}' failed - {}", v, err),
};
@@ -44,7 +44,7 @@ fn test_compute_next_event() -> Result<(), Error> {
};
let test_never = |v: &'static str, last: i64| -> Result<(), Error> {
- let event = match parse_calendar_event(v) {
+ let event: CalendarEvent = match v.parse() {
Ok(event) => event,
Err(err) => bail!("parsing '{}' failed - {}", v, err),
};
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox 14/14] proxmox-time: time-span: implement FromStr
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (12 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 13/14] proxmox-time: calendar_events: implement FromStr Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox-backup 1/1] remove use of deprecated functions from proxmox-time Dominik Csapak
2021-12-01 6:20 ` [pbs-devel] applied: [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dietmar Maurer
15 siblings, 0 replies; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
and deprecate 'parse_time_span'
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
proxmox-time/src/test.rs | 2 +-
proxmox-time/src/time_span.rs | 13 +++++++++++--
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/proxmox-time/src/test.rs b/proxmox-time/src/test.rs
index 0476cc1..ec63a37 100644
--- a/proxmox-time/src/test.rs
+++ b/proxmox-time/src/test.rs
@@ -225,7 +225,7 @@ fn test_calendar_event_weekday() -> Result<(), Error> {
#[test]
fn test_time_span_parser() -> Result<(), Error> {
let test_value = |ts_str: &str, expect: f64| -> Result<(), Error> {
- let ts = parse_time_span(ts_str)?;
+ let ts: TimeSpan = ts_str.parse()?;
assert_eq!(f64::from(ts), expect, "{}", ts_str);
Ok(())
};
diff --git a/proxmox-time/src/time_span.rs b/proxmox-time/src/time_span.rs
index 2f8cf59..0a6c9ca 100644
--- a/proxmox-time/src/time_span.rs
+++ b/proxmox-time/src/time_span.rs
@@ -198,9 +198,18 @@ fn parse_time_unit(i: &str) -> IResult<&str, &str> {
}
}
+impl std::str::FromStr for TimeSpan {
+ type Err = Error;
+
+ fn from_str(i: &str) -> Result<Self, Self::Err> {
+ parse_complete_line("calendar event", i, parse_time_span_incomplete)
+ }
+}
+
/// Parse a [TimeSpan]
+#[deprecated="Use std::str::FromStr trait instead."]
pub fn parse_time_span(i: &str) -> Result<TimeSpan, Error> {
- parse_complete_line("time span", i, parse_time_span_incomplete)
+ i.parse()
}
fn parse_time_span_incomplete(mut i: &str) -> IResult<&str, TimeSpan> {
@@ -259,7 +268,7 @@ fn parse_time_span_incomplete(mut i: &str) -> IResult<&str, TimeSpan> {
/// Verify the format of the [TimeSpan]
pub fn verify_time_span(i: &str) -> Result<(), Error> {
- parse_time_span(i)?;
+ let _: TimeSpan = i.parse()?;
Ok(())
}
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] [PATCH proxmox-backup 1/1] remove use of deprecated functions from proxmox-time
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (13 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 14/14] proxmox-time: time-span: " Dominik Csapak
@ 2021-11-30 12:12 ` Dominik Csapak
2021-12-01 6:26 ` [pbs-devel] applied: " Dietmar Maurer
2021-12-01 6:20 ` [pbs-devel] applied: [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dietmar Maurer
15 siblings, 1 reply; 18+ messages in thread
From: Dominik Csapak @ 2021-11-30 12:12 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
pbs-api-types/src/tape/media_pool.rs | 6 +++---
src/bin/proxmox-backup-proxy.rs | 10 +++++-----
src/server/jobstate.rs | 6 +++---
src/tape/inventory.rs | 3 +--
src/tape/media_pool.rs | 3 +--
src/tape/test/compute_media_state.rs | 4 ++--
6 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/pbs-api-types/src/tape/media_pool.rs b/pbs-api-types/src/tape/media_pool.rs
index 3b1cb0f5..c0cba2bd 100644
--- a/pbs-api-types/src/tape/media_pool.rs
+++ b/pbs-api-types/src/tape/media_pool.rs
@@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
use proxmox_schema::{api, Schema, StringSchema, ApiStringFormat, Updater};
-use proxmox_time::{parse_calendar_event, parse_time_span, CalendarEvent, TimeSpan};
+use proxmox_time::{CalendarEvent, TimeSpan};
use crate::{
PROXMOX_SAFE_ID_FORMAT,
@@ -62,7 +62,7 @@ impl std::str::FromStr for MediaSetPolicy {
return Ok(MediaSetPolicy::AlwaysCreate);
}
- let event = parse_calendar_event(s)?;
+ let event = s.parse()?;
Ok(MediaSetPolicy::CreateAt(event))
}
@@ -97,7 +97,7 @@ impl std::str::FromStr for RetentionPolicy {
return Ok(RetentionPolicy::KeepForever);
}
- let time_span = parse_time_span(s)?;
+ let time_span = s.parse()?;
Ok(RetentionPolicy::ProtectFor(time_span))
}
diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-proxy.rs
index 0d852a7a..16ae67bb 100644
--- a/src/bin/proxmox-backup-proxy.rs
+++ b/src/bin/proxmox-backup-proxy.rs
@@ -47,7 +47,7 @@ use proxmox_backup::{
};
use pbs_buildcfg::configdir;
-use proxmox_time::{compute_next_event, parse_calendar_event};
+use proxmox_time::CalendarEvent;
use pbs_api_types::{
Authid, TapeBackupJobConfig, VerificationJobConfig, SyncJobConfig, DataStoreConfig,
@@ -565,7 +565,7 @@ async fn schedule_datastore_garbage_collection() {
None => continue,
};
- let event = match parse_calendar_event(&event_str) {
+ let event: CalendarEvent = match event_str.parse() {
Ok(event) => event,
Err(err) => {
eprintln!("unable to parse schedule '{}' - {}", event_str, err);
@@ -585,7 +585,7 @@ async fn schedule_datastore_garbage_collection() {
}
};
- let next = match compute_next_event(&event, last, false) {
+ let next = match event.compute_next_event(last, false) {
Ok(Some(next)) => next,
Ok(None) => continue,
Err(err) => {
@@ -1024,7 +1024,7 @@ fn generate_host_stats_sync() {
}
fn check_schedule(worker_type: &str, event_str: &str, id: &str) -> bool {
- let event = match parse_calendar_event(event_str) {
+ let event: CalendarEvent = match event_str.parse() {
Ok(event) => event,
Err(err) => {
eprintln!("unable to parse schedule '{}' - {}", event_str, err);
@@ -1040,7 +1040,7 @@ fn check_schedule(worker_type: &str, event_str: &str, id: &str) -> bool {
}
};
- let next = match compute_next_event(&event, last, false) {
+ let next = match event.compute_next_event(last, false) {
Ok(Some(next)) => next,
Ok(None) => return false,
Err(err) => {
diff --git a/src/server/jobstate.rs b/src/server/jobstate.rs
index adb1bbe2..f874725a 100644
--- a/src/server/jobstate.rs
+++ b/src/server/jobstate.rs
@@ -46,7 +46,7 @@ use proxmox_sys::fs::{
create_path, file_read_optional_string, replace_file, CreateOptions,
};
-use proxmox_time::{compute_next_event, parse_calendar_event};
+use proxmox_time::CalendarEvent;
use pbs_buildcfg::PROXMOX_BACKUP_STATE_DIR_M;
use pbs_config::{open_backup_lockfile, BackupLockGuard};
@@ -339,9 +339,9 @@ pub fn compute_schedule_status(
status.last_run_endtime = endtime;
if let Some(schedule) = schedule {
- if let Ok(event) = parse_calendar_event(&schedule) {
+ if let Ok(event) = schedule.parse::<CalendarEvent>() {
// ignore errors
- status.next_run = compute_next_event(&event, last, false).unwrap_or(None);
+ status.next_run = event.compute_next_event(last, false).unwrap_or(None);
}
}
diff --git a/src/tape/inventory.rs b/src/tape/inventory.rs
index 4ecbb425..1f0b41f8 100644
--- a/src/tape/inventory.rs
+++ b/src/tape/inventory.rs
@@ -33,7 +33,6 @@ use serde_json::json;
use proxmox_sys::fs::{replace_file, file_get_json, CreateOptions};
use proxmox_uuid::Uuid;
-use proxmox_time::compute_next_event;
use pbs_config::BackupLockGuard;
use pbs_api_types::{MediaSetPolicy, RetentionPolicy, MediaStatus, MediaLocation};
@@ -534,7 +533,7 @@ impl Inventory {
set_start_time
}
MediaSetPolicy::CreateAt(ref event) => {
- match compute_next_event(event, set_start_time, false) {
+ match event.compute_next_event(set_start_time, false) {
Ok(Some(next)) => next,
Ok(None) | Err(_) => return i64::MAX,
}
diff --git a/src/tape/media_pool.rs b/src/tape/media_pool.rs
index 68908768..70713cc3 100644
--- a/src/tape/media_pool.rs
+++ b/src/tape/media_pool.rs
@@ -18,7 +18,6 @@ use pbs_api_types::{
Fingerprint, MediaStatus, MediaLocation, MediaSetPolicy, RetentionPolicy,
MediaPoolConfig,
};
-use proxmox_time::compute_next_event;
use pbs_config::BackupLockGuard;
use crate::tape::{
@@ -291,7 +290,7 @@ impl MediaPool {
}
MediaSetPolicy::CreateAt(event) => {
if let Some(set_start_time) = self.inventory.media_set_start_time(&self.current_media_set.uuid()) {
- if let Ok(Some(alloc_time)) = compute_next_event(event, set_start_time as i64, false) {
+ if let Ok(Some(alloc_time)) = event.compute_next_event(set_start_time as i64, false) {
if current_time >= alloc_time {
create_new_set = Some(String::from("policy CreateAt event triggered"));
}
diff --git a/src/tape/test/compute_media_state.rs b/src/tape/test/compute_media_state.rs
index c1dfdba7..78e32190 100644
--- a/src/tape/test/compute_media_state.rs
+++ b/src/tape/test/compute_media_state.rs
@@ -100,8 +100,8 @@ fn test_media_expire_time() -> Result<(), Error> {
let sl2= MediaSetLabel::with_data("p1", Uuid::generate(), 0, ctime + 120, None);
let tape2_uuid = inventory.generate_used_tape("tape2", sl2, 0);
- let event = proxmox_time::parse_calendar_event("*:0/2")?;
- let span = proxmox_time::parse_time_span("120 seconds")?;
+ let event = "*:0/2".parse()?;
+ let span = "120 seconds".parse()?;
let pool = MediaPool::new(
"p1",
--
2.30.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] applied: [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
` (14 preceding siblings ...)
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox-backup 1/1] remove use of deprecated functions from proxmox-time Dominik Csapak
@ 2021-12-01 6:20 ` Dietmar Maurer
15 siblings, 0 replies; 18+ messages in thread
From: Dietmar Maurer @ 2021-12-01 6:20 UTC (permalink / raw)
To: Proxmox Backup Server development discussion, Dominik Csapak
applied
^ permalink raw reply [flat|nested] 18+ messages in thread
* [pbs-devel] applied: [PATCH proxmox-backup 1/1] remove use of deprecated functions from proxmox-time
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox-backup 1/1] remove use of deprecated functions from proxmox-time Dominik Csapak
@ 2021-12-01 6:26 ` Dietmar Maurer
0 siblings, 0 replies; 18+ messages in thread
From: Dietmar Maurer @ 2021-12-01 6:26 UTC (permalink / raw)
To: Proxmox Backup Server development discussion, Dominik Csapak
applied
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2021-12-01 6:26 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-30 12:11 [pbs-devel] [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 01/14] proxmox-time: calendar-events: implement repeated ranges Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 02/14] proxmox-time: calendar-events: make hour optional Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 03/14] proxmox-time: move common parse functions to parse_helpers Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 04/14] proxmox-time: move WeekDays into own file Dominik Csapak
2021-11-30 12:11 ` [pbs-devel] [PATCH proxmox 05/14] proxmox-time: split DateTimeValue " Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 06/14] proxmox-time: move parse_daily_duration to daily_duration.rs Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 07/14] proxmox-time: daily_duration.rs: rustfmt Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 08/14] proxmox-time: move CalendarEvent into calendar_events.rs Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 09/14] proxmox-time: move TimeSpan into time_span.rs Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 10/14] proxmox-time: move tests from time.rs to test.rs Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 11/14] proxmox-time: lib.rs: rustfmt Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 12/14] proxmox-time: calendar-events: make compute_next_event a method Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 13/14] proxmox-time: calendar_events: implement FromStr Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox 14/14] proxmox-time: time-span: " Dominik Csapak
2021-11-30 12:12 ` [pbs-devel] [PATCH proxmox-backup 1/1] remove use of deprecated functions from proxmox-time Dominik Csapak
2021-12-01 6:26 ` [pbs-devel] applied: " Dietmar Maurer
2021-12-01 6:20 ` [pbs-devel] applied: [PATCH proxmox/proxmox-backup 00/14] improve & cleanup proxmox-time Dietmar Maurer
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal