Initial Backupper Unraid plugin
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Expression struct{ fields [5]field }
|
||||
type field map[int]bool
|
||||
|
||||
var bounds = [5][2]int{{0, 59}, {0, 23}, {1, 31}, {1, 12}, {0, 6}}
|
||||
|
||||
func Parse(spec string) (Expression, error) {
|
||||
parts := strings.Fields(spec)
|
||||
if len(parts) != 5 {
|
||||
return Expression{}, fmt.Errorf("cron requires five fields")
|
||||
}
|
||||
var expression Expression
|
||||
for i, part := range parts {
|
||||
parsed, err := parseField(part, bounds[i][0], bounds[i][1])
|
||||
if err != nil {
|
||||
return Expression{}, fmt.Errorf("cron field %d: %w", i+1, err)
|
||||
}
|
||||
expression.fields[i] = parsed
|
||||
}
|
||||
return expression, nil
|
||||
}
|
||||
|
||||
func parseField(value string, min, max int) (field, error) {
|
||||
result := field{}
|
||||
for _, segment := range strings.Split(value, ",") {
|
||||
step := 1
|
||||
base := segment
|
||||
if strings.Contains(segment, "/") {
|
||||
parts := strings.Split(segment, "/")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid step %q", segment)
|
||||
}
|
||||
base = parts[0]
|
||||
var err error
|
||||
step, err = strconv.Atoi(parts[1])
|
||||
if err != nil || step < 1 {
|
||||
return nil, fmt.Errorf("invalid step %q", parts[1])
|
||||
}
|
||||
}
|
||||
start, end := min, max
|
||||
if base != "*" {
|
||||
if strings.Contains(base, "-") {
|
||||
parts := strings.Split(base, "-")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid range %q", base)
|
||||
}
|
||||
start, _ = strconv.Atoi(parts[0])
|
||||
end, _ = strconv.Atoi(parts[1])
|
||||
} else {
|
||||
var err error
|
||||
start, err = strconv.Atoi(base)
|
||||
end = start
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid value %q", base)
|
||||
}
|
||||
}
|
||||
}
|
||||
if start < min || end > max || start > end {
|
||||
return nil, fmt.Errorf("value outside %d-%d", min, max)
|
||||
}
|
||||
for n := start; n <= end; n += step {
|
||||
result[n] = true
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e Expression) Matches(t time.Time) bool {
|
||||
values := [5]int{t.Minute(), t.Hour(), t.Day(), int(t.Month()), int(t.Weekday())}
|
||||
for i, value := range values {
|
||||
if !e.fields[i][value] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (e Expression) Next(after time.Time) time.Time {
|
||||
t := after.Truncate(time.Minute).Add(time.Minute)
|
||||
limit := t.AddDate(2, 0, 0)
|
||||
for t.Before(limit) {
|
||||
if e.Matches(t) {
|
||||
return t
|
||||
}
|
||||
t = t.Add(time.Minute)
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
Reference in New Issue
Block a user