From 2fe190f838bb563f71f9d0d9a0fbb6d14108c2ed Mon Sep 17 00:00:00 2001 From: Maciej Szulik Date: Fri, 10 Mar 2017 12:35:00 +0100 Subject: [PATCH] bump(github.com/robfig/cron): 783cfcb01fb00c48f740c9de79122bd410294149 --- Godeps/Godeps.json | 4 +- vendor/github.com/robfig/cron/cron.go | 12 +- vendor/github.com/robfig/cron/parser.go | 220 ++++++++++++++++-------- vendor/github.com/robfig/cron/spec.go | 1 - 4 files changed, 158 insertions(+), 79 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index a29e3f0f05b..0f63e0650f5 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -2215,8 +2215,8 @@ }, { "ImportPath": "github.com/robfig/cron", - "Comment": "v1-40-g783cfcb", - "Rev": "783cfcb01fb00c48f740c9de79122bd410294149" + "Comment": "v1-53-gdf38d32", + "Rev": "df38d32658d8788cd446ba74db4bb5375c4b0cb3" }, { "ImportPath": "github.com/rubiojr/go-vhd/vhd", diff --git a/vendor/github.com/robfig/cron/cron.go b/vendor/github.com/robfig/cron/cron.go index f648e6dee15..efd534707ec 100644 --- a/vendor/github.com/robfig/cron/cron.go +++ b/vendor/github.com/robfig/cron/cron.go @@ -1,5 +1,3 @@ -// This library implements a cron spec parser and runner. See the README for -// more details. package cron import ( @@ -146,6 +144,15 @@ func (c *Cron) Start() { go c.run() } +// Run the cron scheduler, or no-op if already running. +func (c *Cron) Run() { + if c.running { + return + } + c.running = true + c.run() +} + func (c *Cron) runWithRecovery(j Job) { defer func() { if r := recover(); r != nil { @@ -183,6 +190,7 @@ func (c *Cron) run() { timer := time.NewTimer(effective.Sub(now)) select { case now = <-timer.C: + now = now.In(c.location) // Run every entry whose next time was this effective time. for _, e := range c.entries { if e.Next != effective { diff --git a/vendor/github.com/robfig/cron/parser.go b/vendor/github.com/robfig/cron/parser.go index d6c73c220b7..a5e83c0a8dc 100644 --- a/vendor/github.com/robfig/cron/parser.go +++ b/vendor/github.com/robfig/cron/parser.go @@ -8,88 +8,114 @@ import ( "time" ) -// ParseStandard returns a new crontab schedule representing the given standardSpec -// (https://en.wikipedia.org/wiki/Cron). It differs from Parse requiring to always -// pass 5 entries representing: minute, hour, day of month, month and day of week, -// in that order. It returns a descriptive error if the spec is not valid. +// Configuration options for creating a parser. Most options specify which +// fields should be included, while others enable features. If a field is not +// included the parser will assume a default value. These options do not change +// the order fields are parse in. +type ParseOption int + +const ( + Second ParseOption = 1 << iota // Seconds field, default 0 + Minute // Minutes field, default 0 + Hour // Hours field, default 0 + Dom // Day of month field, default * + Month // Month field, default * + Dow // Day of week field, default * + DowOptional // Optional day of week field, default * + Descriptor // Allow descriptors such as @monthly, @weekly, etc. +) + +var places = []ParseOption{ + Second, + Minute, + Hour, + Dom, + Month, + Dow, +} + +var defaults = []string{ + "0", + "0", + "0", + "*", + "*", + "*", +} + +// A custom Parser that can be configured. +type Parser struct { + options ParseOption + optionals int +} + +// Creates a custom Parser with custom options. // -// It accepts -// - Standard crontab specs, e.g. "* * * * ?" -// - Descriptors, e.g. "@midnight", "@every 1h30m" -func ParseStandard(standardSpec string) (Schedule, error) { - if standardSpec[0] == '@' { - return parseDescriptor(standardSpec) +// // Standard parser without descriptors +// specParser := NewParser(Minute | Hour | Dom | Month | Dow) +// sched, err := specParser.Parse("0 0 15 */3 *") +// +// // Same as above, just excludes time fields +// subsParser := NewParser(Dom | Month | Dow) +// sched, err := specParser.Parse("15 */3 *") +// +// // Same as above, just makes Dow optional +// subsParser := NewParser(Dom | Month | DowOptional) +// sched, err := specParser.Parse("15 */3") +// +func NewParser(options ParseOption) Parser { + optionals := 0 + if options&DowOptional > 0 { + options |= Dow + optionals++ } - - // Split on whitespace. We require exactly 5 fields. - // (minute) (hour) (day of month) (month) (day of week) - fields := strings.Fields(standardSpec) - if len(fields) != 5 { - return nil, fmt.Errorf("Expected exactly 5 fields, found %d: %s", len(fields), standardSpec) - } - - var err error - field := func(field string, r bounds) uint64 { - if err != nil { - return uint64(0) - } - var bits uint64 - bits, err = getField(field, r) - return bits - } - var ( - minute = field(fields[0], minutes) - hour = field(fields[1], hours) - dayofmonth = field(fields[2], dom) - month = field(fields[3], months) - dayofweek = field(fields[4], dow) - ) - if err != nil { - return nil, err - } - - return &SpecSchedule{ - Second: 1 << seconds.min, - Minute: minute, - Hour: hour, - Dom: dayofmonth, - Month: month, - Dow: dayofweek, - }, nil + return Parser{options, optionals} } // Parse returns a new crontab schedule representing the given spec. // It returns a descriptive error if the spec is not valid. -// -// It accepts -// - Full crontab specs, e.g. "* * * * * ?" -// - Descriptors, e.g. "@midnight", "@every 1h30m" -func Parse(spec string) (Schedule, error) { - if spec[0] == '@' { +// It accepts crontab specs and features configured by NewParser. +func (p Parser) Parse(spec string) (Schedule, error) { + if len(spec) == 0 { + return nil, fmt.Errorf("Empty spec string") + } + if spec[0] == '@' && p.options&Descriptor > 0 { return parseDescriptor(spec) } - // Split on whitespace. We require 5 or 6 fields. - // (second) (minute) (hour) (day of month) (month) (day of week, optional) + // Figure out how many fields we need + max := 0 + for _, place := range places { + if p.options&place > 0 { + max++ + } + } + min := max - p.optionals + + // Split fields on whitespace fields := strings.Fields(spec) - if len(fields) != 5 && len(fields) != 6 { - return nil, fmt.Errorf("Expected 5 or 6 fields, found %d: %s", len(fields), spec) + + // Validate number of fields + if count := len(fields); count < min || count > max { + if min == max { + return nil, fmt.Errorf("Expected exactly %d fields, found %d: %s", min, count, spec) + } + return nil, fmt.Errorf("Expected %d to %d fields, found %d: %s", min, max, count, spec) } - // If a sixth field is not provided (DayOfWeek), then it is equivalent to star. - if len(fields) == 5 { - fields = append(fields, "*") - } + // Fill in missing fields + fields = expandFields(fields, p.options) var err error field := func(field string, r bounds) uint64 { if err != nil { - return uint64(0) + return 0 } var bits uint64 bits, err = getField(field, r) return bits } + var ( second = field(fields[0], seconds) minute = field(fields[1], minutes) @@ -112,6 +138,53 @@ func Parse(spec string) (Schedule, error) { }, nil } +func expandFields(fields []string, options ParseOption) []string { + n := 0 + count := len(fields) + expFields := make([]string, len(places)) + copy(expFields, defaults) + for i, place := range places { + if options&place > 0 { + expFields[i] = fields[n] + n++ + } + if n == count { + break + } + } + return expFields +} + +var standardParser = NewParser( + Minute | Hour | Dom | Month | Dow | Descriptor, +) + +// ParseStandard returns a new crontab schedule representing the given standardSpec +// (https://en.wikipedia.org/wiki/Cron). It differs from Parse requiring to always +// pass 5 entries representing: minute, hour, day of month, month and day of week, +// in that order. It returns a descriptive error if the spec is not valid. +// +// It accepts +// - Standard crontab specs, e.g. "* * * * ?" +// - Descriptors, e.g. "@midnight", "@every 1h30m" +func ParseStandard(standardSpec string) (Schedule, error) { + return standardParser.Parse(standardSpec) +} + +var defaultParser = NewParser( + Second | Minute | Hour | Dom | Month | DowOptional | Descriptor, +) + +// Parse returns a new crontab schedule representing the given spec. +// It returns a descriptive error if the spec is not valid. +// +// It accepts +// - Full crontab specs, e.g. "* * * * * ?" +// - Descriptors, e.g. "@midnight", "@every 1h30m" +func Parse(spec string) (Schedule, error) { + return defaultParser.Parse(spec) +} + // getField returns an Int with the bits set representing all of the times that // the field represents or error parsing field value. A "field" is a comma-separated // list of "ranges". @@ -138,18 +211,17 @@ func getRange(expr string, r bounds) (uint64, error) { lowAndHigh = strings.Split(rangeAndStep[0], "-") singleDigit = len(lowAndHigh) == 1 err error - zero = uint64(0) ) - var extra_star uint64 + var extra uint64 if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" { start = r.min end = r.max - extra_star = starBit + extra = starBit } else { start, err = parseIntOrName(lowAndHigh[0], r.names) if err != nil { - return zero, err + return 0, err } switch len(lowAndHigh) { case 1: @@ -157,10 +229,10 @@ func getRange(expr string, r bounds) (uint64, error) { case 2: end, err = parseIntOrName(lowAndHigh[1], r.names) if err != nil { - return zero, err + return 0, err } default: - return zero, fmt.Errorf("Too many hyphens: %s", expr) + return 0, fmt.Errorf("Too many hyphens: %s", expr) } } @@ -170,7 +242,7 @@ func getRange(expr string, r bounds) (uint64, error) { case 2: step, err = mustParseInt(rangeAndStep[1]) if err != nil { - return zero, err + return 0, err } // Special handling: "N/step" means "N-max/step". @@ -178,23 +250,23 @@ func getRange(expr string, r bounds) (uint64, error) { end = r.max } default: - return zero, fmt.Errorf("Too many slashes: %s", expr) + return 0, fmt.Errorf("Too many slashes: %s", expr) } if start < r.min { - return zero, fmt.Errorf("Beginning of range (%d) below minimum (%d): %s", start, r.min, expr) + return 0, fmt.Errorf("Beginning of range (%d) below minimum (%d): %s", start, r.min, expr) } if end > r.max { - return zero, fmt.Errorf("End of range (%d) above maximum (%d): %s", end, r.max, expr) + return 0, fmt.Errorf("End of range (%d) above maximum (%d): %s", end, r.max, expr) } if start > end { - return zero, fmt.Errorf("Beginning of range (%d) beyond end of range (%d): %s", start, end, expr) + return 0, fmt.Errorf("Beginning of range (%d) beyond end of range (%d): %s", start, end, expr) } if step == 0 { - return zero, fmt.Errorf("Step of range should be a positive number: %s", expr) + return 0, fmt.Errorf("Step of range should be a positive number: %s", expr) } - return getBits(start, end, step) | extra_star, nil + return getBits(start, end, step) | extra, nil } // parseIntOrName returns the (possibly-named) integer contained in expr. diff --git a/vendor/github.com/robfig/cron/spec.go b/vendor/github.com/robfig/cron/spec.go index 2b541269522..aac9a60b954 100644 --- a/vendor/github.com/robfig/cron/spec.go +++ b/vendor/github.com/robfig/cron/spec.go @@ -151,7 +151,6 @@ func dayMatches(s *SpecSchedule, t time.Time) bool { domMatch bool = 1< 0 dowMatch bool = 1< 0 ) - if s.Dom&starBit > 0 || s.Dow&starBit > 0 { return domMatch && dowMatch }