Initial Backupper Unraid plugin

This commit is contained in:
Mikei386
2026-06-13 22:07:31 +02:00
commit 5352a9da22
39 changed files with 3167 additions and 0 deletions
+96
View File
@@ -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{}
}