Skip to content

Commit

Permalink
Merge pull request #180 from wishdev/cron_parser
Browse files Browse the repository at this point in the history
Cron ranges
  • Loading branch information
bakpakin authored Apr 15, 2024
2 parents 86d7fd7 + a95f598 commit 19787cc
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 13 deletions.
46 changes: 34 additions & 12 deletions spork/cron.janet
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
###
### The cron format support is based on the unix cron syntax, with an optional
### seconds field. Each field can be a comma separated list of individual values
### or a range of values. A range is specified by two values with a "-" between them, optionally
### followed by a "/" and a step value. An asterisk ("*") can be used to denote all possible values.
### or a range of values.
### A range has three variants as follows
### Two values with a "-" between them, optionally followed by a "/" and a step value.
### An asterisk ("*") followed by a "/" and a step value. This implies every "step" value.
### A single value followed by a "/" and a step value. This implies every "step" value
### starting with the single value. i.e. 2/3 implies every 3 units from 2 to max units.
### A single asterisk ("*") can be used to denote all possible values.
###
### The fields:
### * minutes: 0-59
Expand Down Expand Up @@ -89,16 +94,29 @@
[start &opt end step]
(default end start)
(default step 1)
[start end step])
(if (= start :*)
[start start end]
(if (and (string? start) (string/has-suffix? "*" start))
[(scan-number (string/replace "*" "" start)) :* end]
[start end step])))

(def- cron-peg
(peg/compile
~{:3code '(some :a)
:num (+ (/ ':d+ ,scan-number) :3code)
:range (/ (* :num (? (* "-" :num (? (* "/" :num))))) ,capture-range)
:range-group (group (* :range (any (* "," :range))))
:star (* "*" (constant :*))
:field (+ :star :range-group)
:start (/ ':d+ ,|(string $0 "*"))
:num-range (* :num "-" :num)

:slash-left (+ :star :num-range :start)
:slash (* :slash-left "/" :num)

:range (+ :slash :num-range :num)
:range-val (/ :range ,capture-range)
:range-group (group (* :range-val (any (* "," :range-val))))

:field (+ :range-group :star)

:main (* :field :s+ :field :s+ :field :s+ :field :s+ :field :s*
(? (* :field :s*)) -1)}))

Expand All @@ -111,12 +129,16 @@
(bitmap-setrange bitmap (+ offset mini) (+ offset maxi))
(do
(each [start end step] ranges
(def start (if (and codes (string? start))
(- (assert (in codes (string/ascii-lower start)) (string "invalid code " start)) offset)
start))
(def end (if (and codes (string? end))
(- (assert (in codes (string/ascii-lower end)) (string "invalid code " end)) offset)
end))
(def start (if (= :* start)
mini
(if (and codes (string? start))
(- (assert (in codes (string/ascii-lower start)) (string "invalid code " start)) offset)
start)))
(def end (if (= :* end)
maxi
(if (and codes (string? end))
(- (assert (in codes (string/ascii-lower end)) (string "invalid code " end)) offset)
end)))
(assert (>= start mini) (string "invalid " debug-name ": " start))
(assert (<= end maxi) (string "invalid " debug-name ": " end))
(bitmap-setrange bitmap (+ offset start) (+ offset end) step))
Expand Down
7 changes: 6 additions & 1 deletion test/suite-cron.janet
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
(map print (get-sequence cron n start-time local)))

# Pick a stable start time
(def stable-start 1665693611)
(def stable-start 1665693600)

(assert (deep= (get-sequence "10 14 * jan mon,tue" 10 stable-start)
@["2023-01-02 14:10:00"
Expand All @@ -47,4 +47,9 @@
"2023-01-30 14:10:00"
"2023-01-31 14:10:00"]) "sequence 1")

(assert (cron/check "40 * * * *" stable-start))
(assert (cron/check "5,40 * * * *" stable-start))
(assert (cron/check "10/5 * * * *" stable-start))
(assert (cron/check "*/5 * * * *" stable-start))

(end-suite)

0 comments on commit 19787cc

Please sign in to comment.