mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Adding github.com/robfig/cron for cron parsing
This commit is contained in:
		
							
								
								
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							@@ -1760,6 +1760,10 @@
 | 
			
		||||
			"Comment": "v1.0.0-842-g8992d74",
 | 
			
		||||
			"Rev": "8992d7483a06748dea706e4716d042a4a9e73918"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/robfig/cron",
 | 
			
		||||
			"Rev": "0f39cf7ebc65a602f45692f9894bd6a193faf8fa"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/russross/blackfriday",
 | 
			
		||||
			"Comment": "v1.2-42-g77efab5",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								Godeps/LICENSES
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										26
									
								
								Godeps/LICENSES
									
									
									
										generated
									
									
									
								
							@@ -59125,6 +59125,32 @@ specific language governing permissions and limitations under the License.
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
================================================================================
 | 
			
		||||
= vendor/github.com/robfig/cron licensed under: =
 | 
			
		||||
 | 
			
		||||
Copyright (C) 2012 Rob Figueiredo
 | 
			
		||||
All Rights Reserved.
 | 
			
		||||
 | 
			
		||||
MIT LICENSE
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
the Software without restriction, including without limitation the rights to
 | 
			
		||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 | 
			
		||||
the Software, and to permit persons to whom the Software is furnished to do so,
 | 
			
		||||
subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 | 
			
		||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
			
		||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
			
		||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
================================================================================
 | 
			
		||||
= vendor/github.com/russross/blackfriday licensed under: =
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/robfig/cron/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/robfig/cron/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
 | 
			
		||||
*.o
 | 
			
		||||
*.a
 | 
			
		||||
*.so
 | 
			
		||||
 | 
			
		||||
# Folders
 | 
			
		||||
_obj
 | 
			
		||||
_test
 | 
			
		||||
 | 
			
		||||
# Architecture specific extensions/prefixes
 | 
			
		||||
*.[568vq]
 | 
			
		||||
[568vq].out
 | 
			
		||||
 | 
			
		||||
*.cgo1.go
 | 
			
		||||
*.cgo2.c
 | 
			
		||||
_cgo_defun.c
 | 
			
		||||
_cgo_gotypes.go
 | 
			
		||||
_cgo_export.*
 | 
			
		||||
 | 
			
		||||
_testmain.go
 | 
			
		||||
 | 
			
		||||
*.exe
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/robfig/cron/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/robfig/cron/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
language: go
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/robfig/cron/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/robfig/cron/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
Copyright (C) 2012 Rob Figueiredo
 | 
			
		||||
All Rights Reserved.
 | 
			
		||||
 | 
			
		||||
MIT LICENSE
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
the Software without restriction, including without limitation the rights to
 | 
			
		||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 | 
			
		||||
the Software, and to permit persons to whom the Software is furnished to do so,
 | 
			
		||||
subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 | 
			
		||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
			
		||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
			
		||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/robfig/cron/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/robfig/cron/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
[](http://godoc.org/github.com/robfig/cron)
 | 
			
		||||
[](https://travis-ci.org/robfig/cron)
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/github.com/robfig/cron/constantdelay.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/robfig/cron/constantdelay.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
package cron
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes".
 | 
			
		||||
// It does not support jobs more frequent than once a second.
 | 
			
		||||
type ConstantDelaySchedule struct {
 | 
			
		||||
	Delay time.Duration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Every returns a crontab Schedule that activates once every duration.
 | 
			
		||||
// Delays of less than a second are not supported (will round up to 1 second).
 | 
			
		||||
// Any fields less than a Second are truncated.
 | 
			
		||||
func Every(duration time.Duration) ConstantDelaySchedule {
 | 
			
		||||
	if duration < time.Second {
 | 
			
		||||
		duration = time.Second
 | 
			
		||||
	}
 | 
			
		||||
	return ConstantDelaySchedule{
 | 
			
		||||
		Delay: duration - time.Duration(duration.Nanoseconds())%time.Second,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Next returns the next time this should be run.
 | 
			
		||||
// This rounds so that the next activation time will be on the second.
 | 
			
		||||
func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time {
 | 
			
		||||
	return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										227
									
								
								vendor/github.com/robfig/cron/cron.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								vendor/github.com/robfig/cron/cron.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
// This library implements a cron spec parser and runner.  See the README for
 | 
			
		||||
// more details.
 | 
			
		||||
package cron
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Cron keeps track of any number of entries, invoking the associated func as
 | 
			
		||||
// specified by the schedule. It may be started, stopped, and the entries may
 | 
			
		||||
// be inspected while running.
 | 
			
		||||
type Cron struct {
 | 
			
		||||
	entries  []*Entry
 | 
			
		||||
	stop     chan struct{}
 | 
			
		||||
	add      chan *Entry
 | 
			
		||||
	snapshot chan []*Entry
 | 
			
		||||
	running  bool
 | 
			
		||||
	ErrorLog *log.Logger
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Job is an interface for submitted cron jobs.
 | 
			
		||||
type Job interface {
 | 
			
		||||
	Run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The Schedule describes a job's duty cycle.
 | 
			
		||||
type Schedule interface {
 | 
			
		||||
	// Return the next activation time, later than the given time.
 | 
			
		||||
	// Next is invoked initially, and then each time the job is run.
 | 
			
		||||
	Next(time.Time) time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Entry consists of a schedule and the func to execute on that schedule.
 | 
			
		||||
type Entry struct {
 | 
			
		||||
	// The schedule on which this job should be run.
 | 
			
		||||
	Schedule Schedule
 | 
			
		||||
 | 
			
		||||
	// The next time the job will run. This is the zero time if Cron has not been
 | 
			
		||||
	// started or this entry's schedule is unsatisfiable
 | 
			
		||||
	Next time.Time
 | 
			
		||||
 | 
			
		||||
	// The last time this job was run. This is the zero time if the job has never
 | 
			
		||||
	// been run.
 | 
			
		||||
	Prev time.Time
 | 
			
		||||
 | 
			
		||||
	// The Job to run.
 | 
			
		||||
	Job Job
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// byTime is a wrapper for sorting the entry array by time
 | 
			
		||||
// (with zero time at the end).
 | 
			
		||||
type byTime []*Entry
 | 
			
		||||
 | 
			
		||||
func (s byTime) Len() int      { return len(s) }
 | 
			
		||||
func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 | 
			
		||||
func (s byTime) Less(i, j int) bool {
 | 
			
		||||
	// Two zero times should return false.
 | 
			
		||||
	// Otherwise, zero is "greater" than any other time.
 | 
			
		||||
	// (To sort it at the end of the list.)
 | 
			
		||||
	if s[i].Next.IsZero() {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if s[j].Next.IsZero() {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return s[i].Next.Before(s[j].Next)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new Cron job runner.
 | 
			
		||||
func New() *Cron {
 | 
			
		||||
	return &Cron{
 | 
			
		||||
		entries:  nil,
 | 
			
		||||
		add:      make(chan *Entry),
 | 
			
		||||
		stop:     make(chan struct{}),
 | 
			
		||||
		snapshot: make(chan []*Entry),
 | 
			
		||||
		running:  false,
 | 
			
		||||
		ErrorLog: nil,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A wrapper that turns a func() into a cron.Job
 | 
			
		||||
type FuncJob func()
 | 
			
		||||
 | 
			
		||||
func (f FuncJob) Run() { f() }
 | 
			
		||||
 | 
			
		||||
// AddFunc adds a func to the Cron to be run on the given schedule.
 | 
			
		||||
func (c *Cron) AddFunc(spec string, cmd func()) error {
 | 
			
		||||
	return c.AddJob(spec, FuncJob(cmd))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddJob adds a Job to the Cron to be run on the given schedule.
 | 
			
		||||
func (c *Cron) AddJob(spec string, cmd Job) error {
 | 
			
		||||
	schedule, err := Parse(spec)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	c.Schedule(schedule, cmd)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Schedule adds a Job to the Cron to be run on the given schedule.
 | 
			
		||||
func (c *Cron) Schedule(schedule Schedule, cmd Job) {
 | 
			
		||||
	entry := &Entry{
 | 
			
		||||
		Schedule: schedule,
 | 
			
		||||
		Job:      cmd,
 | 
			
		||||
	}
 | 
			
		||||
	if !c.running {
 | 
			
		||||
		c.entries = append(c.entries, entry)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.add <- entry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Entries returns a snapshot of the cron entries.
 | 
			
		||||
func (c *Cron) Entries() []*Entry {
 | 
			
		||||
	if c.running {
 | 
			
		||||
		c.snapshot <- nil
 | 
			
		||||
		x := <-c.snapshot
 | 
			
		||||
		return x
 | 
			
		||||
	}
 | 
			
		||||
	return c.entrySnapshot()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Start the cron scheduler in its own go-routine.
 | 
			
		||||
func (c *Cron) Start() {
 | 
			
		||||
	c.running = true
 | 
			
		||||
	go c.run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Cron) runWithRecovery(j Job) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if r := recover(); r != nil {
 | 
			
		||||
			const size = 64 << 10
 | 
			
		||||
			buf := make([]byte, size)
 | 
			
		||||
			buf = buf[:runtime.Stack(buf, false)]
 | 
			
		||||
			c.logf("cron: panic running job: %v\n%s", r, buf)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	j.Run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Run the scheduler.. this is private just due to the need to synchronize
 | 
			
		||||
// access to the 'running' state variable.
 | 
			
		||||
func (c *Cron) run() {
 | 
			
		||||
	// Figure out the next activation times for each entry.
 | 
			
		||||
	now := time.Now().Local()
 | 
			
		||||
	for _, entry := range c.entries {
 | 
			
		||||
		entry.Next = entry.Schedule.Next(now)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		// Determine the next entry to run.
 | 
			
		||||
		sort.Sort(byTime(c.entries))
 | 
			
		||||
 | 
			
		||||
		var effective time.Time
 | 
			
		||||
		if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
 | 
			
		||||
			// If there are no entries yet, just sleep - it still handles new entries
 | 
			
		||||
			// and stop requests.
 | 
			
		||||
			effective = now.AddDate(10, 0, 0)
 | 
			
		||||
		} else {
 | 
			
		||||
			effective = c.entries[0].Next
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case now = <-time.After(effective.Sub(now)):
 | 
			
		||||
			// Run every entry whose next time was this effective time.
 | 
			
		||||
			for _, e := range c.entries {
 | 
			
		||||
				if e.Next != effective {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
				go c.runWithRecovery(e.Job)
 | 
			
		||||
				e.Prev = e.Next
 | 
			
		||||
				e.Next = e.Schedule.Next(effective)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
 | 
			
		||||
		case newEntry := <-c.add:
 | 
			
		||||
			c.entries = append(c.entries, newEntry)
 | 
			
		||||
			newEntry.Next = newEntry.Schedule.Next(time.Now().Local())
 | 
			
		||||
 | 
			
		||||
		case <-c.snapshot:
 | 
			
		||||
			c.snapshot <- c.entrySnapshot()
 | 
			
		||||
 | 
			
		||||
		case <-c.stop:
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 'now' should be updated after newEntry and snapshot cases.
 | 
			
		||||
		now = time.Now().Local()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logs an error to stderr or to the configured error log
 | 
			
		||||
func (c *Cron) logf(format string, args ...interface{}) {
 | 
			
		||||
	if c.ErrorLog != nil {
 | 
			
		||||
		c.ErrorLog.Printf(format, args...)
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Printf(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Stop stops the cron scheduler if it is running; otherwise it does nothing.
 | 
			
		||||
func (c *Cron) Stop() {
 | 
			
		||||
	if !c.running {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c.stop <- struct{}{}
 | 
			
		||||
	c.running = false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// entrySnapshot returns a copy of the current cron entry list.
 | 
			
		||||
func (c *Cron) entrySnapshot() []*Entry {
 | 
			
		||||
	entries := []*Entry{}
 | 
			
		||||
	for _, e := range c.entries {
 | 
			
		||||
		entries = append(entries, &Entry{
 | 
			
		||||
			Schedule: e.Schedule,
 | 
			
		||||
			Next:     e.Next,
 | 
			
		||||
			Prev:     e.Prev,
 | 
			
		||||
			Job:      e.Job,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return entries
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										129
									
								
								vendor/github.com/robfig/cron/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								vendor/github.com/robfig/cron/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
/*
 | 
			
		||||
Package cron implements a cron spec parser and job runner.
 | 
			
		||||
 | 
			
		||||
Usage
 | 
			
		||||
 | 
			
		||||
Callers may register Funcs to be invoked on a given schedule.  Cron will run
 | 
			
		||||
them in their own goroutines.
 | 
			
		||||
 | 
			
		||||
	c := cron.New()
 | 
			
		||||
	c.AddFunc("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") })
 | 
			
		||||
	c.AddFunc("@hourly",      func() { fmt.Println("Every hour") })
 | 
			
		||||
	c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") })
 | 
			
		||||
	c.Start()
 | 
			
		||||
	..
 | 
			
		||||
	// Funcs are invoked in their own goroutine, asynchronously.
 | 
			
		||||
	...
 | 
			
		||||
	// Funcs may also be added to a running Cron
 | 
			
		||||
	c.AddFunc("@daily", func() { fmt.Println("Every day") })
 | 
			
		||||
	..
 | 
			
		||||
	// Inspect the cron job entries' next and previous run times.
 | 
			
		||||
	inspect(c.Entries())
 | 
			
		||||
	..
 | 
			
		||||
	c.Stop()  // Stop the scheduler (does not stop any jobs already running).
 | 
			
		||||
 | 
			
		||||
CRON Expression Format
 | 
			
		||||
 | 
			
		||||
A cron expression represents a set of times, using 6 space-separated fields.
 | 
			
		||||
 | 
			
		||||
	Field name   | Mandatory? | Allowed values  | Allowed special characters
 | 
			
		||||
	----------   | ---------- | --------------  | --------------------------
 | 
			
		||||
	Seconds      | Yes        | 0-59            | * / , -
 | 
			
		||||
	Minutes      | Yes        | 0-59            | * / , -
 | 
			
		||||
	Hours        | Yes        | 0-23            | * / , -
 | 
			
		||||
	Day of month | Yes        | 1-31            | * / , - ?
 | 
			
		||||
	Month        | Yes        | 1-12 or JAN-DEC | * / , -
 | 
			
		||||
	Day of week  | Yes        | 0-6 or SUN-SAT  | * / , - ?
 | 
			
		||||
 | 
			
		||||
Note: Month and Day-of-week field values are case insensitive.  "SUN", "Sun",
 | 
			
		||||
and "sun" are equally accepted.
 | 
			
		||||
 | 
			
		||||
Special Characters
 | 
			
		||||
 | 
			
		||||
Asterisk ( * )
 | 
			
		||||
 | 
			
		||||
The asterisk indicates that the cron expression will match for all values of the
 | 
			
		||||
field; e.g., using an asterisk in the 5th field (month) would indicate every
 | 
			
		||||
month.
 | 
			
		||||
 | 
			
		||||
Slash ( / )
 | 
			
		||||
 | 
			
		||||
Slashes are used to describe increments of ranges. For example 3-59/15 in the
 | 
			
		||||
1st field (minutes) would indicate the 3rd minute of the hour and every 15
 | 
			
		||||
minutes thereafter. The form "*\/..." is equivalent to the form "first-last/...",
 | 
			
		||||
that is, an increment over the largest possible range of the field.  The form
 | 
			
		||||
"N/..." is accepted as meaning "N-MAX/...", that is, starting at N, use the
 | 
			
		||||
increment until the end of that specific range.  It does not wrap around.
 | 
			
		||||
 | 
			
		||||
Comma ( , )
 | 
			
		||||
 | 
			
		||||
Commas are used to separate items of a list. For example, using "MON,WED,FRI" in
 | 
			
		||||
the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.
 | 
			
		||||
 | 
			
		||||
Hyphen ( - )
 | 
			
		||||
 | 
			
		||||
Hyphens are used to define ranges. For example, 9-17 would indicate every
 | 
			
		||||
hour between 9am and 5pm inclusive.
 | 
			
		||||
 | 
			
		||||
Question mark ( ? )
 | 
			
		||||
 | 
			
		||||
Question mark may be used instead of '*' for leaving either day-of-month or
 | 
			
		||||
day-of-week blank.
 | 
			
		||||
 | 
			
		||||
Predefined schedules
 | 
			
		||||
 | 
			
		||||
You may use one of several pre-defined schedules in place of a cron expression.
 | 
			
		||||
 | 
			
		||||
	Entry                  | Description                                | Equivalent To
 | 
			
		||||
	-----                  | -----------                                | -------------
 | 
			
		||||
	@yearly (or @annually) | Run once a year, midnight, Jan. 1st        | 0 0 0 1 1 *
 | 
			
		||||
	@monthly               | Run once a month, midnight, first of month | 0 0 0 1 * *
 | 
			
		||||
	@weekly                | Run once a week, midnight on Sunday        | 0 0 0 * * 0
 | 
			
		||||
	@daily (or @midnight)  | Run once a day, midnight                   | 0 0 0 * * *
 | 
			
		||||
	@hourly                | Run once an hour, beginning of hour        | 0 0 * * * *
 | 
			
		||||
 | 
			
		||||
Intervals
 | 
			
		||||
 | 
			
		||||
You may also schedule a job to execute at fixed intervals.  This is supported by
 | 
			
		||||
formatting the cron spec like this:
 | 
			
		||||
 | 
			
		||||
    @every <duration>
 | 
			
		||||
 | 
			
		||||
where "duration" is a string accepted by time.ParseDuration
 | 
			
		||||
(http://golang.org/pkg/time/#ParseDuration).
 | 
			
		||||
 | 
			
		||||
For example, "@every 1h30m10s" would indicate a schedule that activates every
 | 
			
		||||
1 hour, 30 minutes, 10 seconds.
 | 
			
		||||
 | 
			
		||||
Note: The interval does not take the job runtime into account.  For example,
 | 
			
		||||
if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,
 | 
			
		||||
it will have only 2 minutes of idle time between each run.
 | 
			
		||||
 | 
			
		||||
Time zones
 | 
			
		||||
 | 
			
		||||
All interpretation and scheduling is done in the machine's local time zone (as
 | 
			
		||||
provided by the Go time package (http://www.golang.org/pkg/time).
 | 
			
		||||
 | 
			
		||||
Be aware that jobs scheduled during daylight-savings leap-ahead transitions will
 | 
			
		||||
not be run!
 | 
			
		||||
 | 
			
		||||
Thread safety
 | 
			
		||||
 | 
			
		||||
Since the Cron service runs concurrently with the calling code, some amount of
 | 
			
		||||
care must be taken to ensure proper synchronization.
 | 
			
		||||
 | 
			
		||||
All cron methods are designed to be correctly synchronized as long as the caller
 | 
			
		||||
ensures that invocations have a clear happens-before ordering between them.
 | 
			
		||||
 | 
			
		||||
Implementation
 | 
			
		||||
 | 
			
		||||
Cron entries are stored in an array, sorted by their next activation time.  Cron
 | 
			
		||||
sleeps until the next job is due to be run.
 | 
			
		||||
 | 
			
		||||
Upon waking:
 | 
			
		||||
 - it runs each entry that is active on that second
 | 
			
		||||
 - it calculates the next run times for the jobs that were run
 | 
			
		||||
 - it re-sorts the array of entries by next activation time.
 | 
			
		||||
 - it goes to sleep until the soonest job.
 | 
			
		||||
*/
 | 
			
		||||
package cron
 | 
			
		||||
							
								
								
									
										231
									
								
								vendor/github.com/robfig/cron/parser.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								vendor/github.com/robfig/cron/parser.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,231 @@
 | 
			
		||||
package cron
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"math"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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, err error) {
 | 
			
		||||
	// Convert panics into errors
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if recovered := recover(); recovered != nil {
 | 
			
		||||
			err = fmt.Errorf("%v", recovered)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if spec[0] == '@' {
 | 
			
		||||
		return parseDescriptor(spec), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Split on whitespace.  We require 5 or 6 fields.
 | 
			
		||||
	// (second) (minute) (hour) (day of month) (month) (day of week, optional)
 | 
			
		||||
	fields := strings.Fields(spec)
 | 
			
		||||
	if len(fields) != 5 && len(fields) != 6 {
 | 
			
		||||
		log.Panicf("Expected 5 or 6 fields, found %d: %s", len(fields), spec)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If a sixth field is not provided (DayOfWeek), then it is equivalent to star.
 | 
			
		||||
	if len(fields) == 5 {
 | 
			
		||||
		fields = append(fields, "*")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	schedule := &SpecSchedule{
 | 
			
		||||
		Second: getField(fields[0], seconds),
 | 
			
		||||
		Minute: getField(fields[1], minutes),
 | 
			
		||||
		Hour:   getField(fields[2], hours),
 | 
			
		||||
		Dom:    getField(fields[3], dom),
 | 
			
		||||
		Month:  getField(fields[4], months),
 | 
			
		||||
		Dow:    getField(fields[5], dow),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return schedule, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getField returns an Int with the bits set representing all of the times that
 | 
			
		||||
// the field represents.  A "field" is a comma-separated list of "ranges".
 | 
			
		||||
func getField(field string, r bounds) uint64 {
 | 
			
		||||
	// list = range {"," range}
 | 
			
		||||
	var bits uint64
 | 
			
		||||
	ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' })
 | 
			
		||||
	for _, expr := range ranges {
 | 
			
		||||
		bits |= getRange(expr, r)
 | 
			
		||||
	}
 | 
			
		||||
	return bits
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getRange returns the bits indicated by the given expression:
 | 
			
		||||
//   number | number "-" number [ "/" number ]
 | 
			
		||||
func getRange(expr string, r bounds) uint64 {
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		start, end, step uint
 | 
			
		||||
		rangeAndStep     = strings.Split(expr, "/")
 | 
			
		||||
		lowAndHigh       = strings.Split(rangeAndStep[0], "-")
 | 
			
		||||
		singleDigit      = len(lowAndHigh) == 1
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	var extra_star uint64
 | 
			
		||||
	if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" {
 | 
			
		||||
		start = r.min
 | 
			
		||||
		end = r.max
 | 
			
		||||
		extra_star = starBit
 | 
			
		||||
	} else {
 | 
			
		||||
		start = parseIntOrName(lowAndHigh[0], r.names)
 | 
			
		||||
		switch len(lowAndHigh) {
 | 
			
		||||
		case 1:
 | 
			
		||||
			end = start
 | 
			
		||||
		case 2:
 | 
			
		||||
			end = parseIntOrName(lowAndHigh[1], r.names)
 | 
			
		||||
		default:
 | 
			
		||||
			log.Panicf("Too many hyphens: %s", expr)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch len(rangeAndStep) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		step = 1
 | 
			
		||||
	case 2:
 | 
			
		||||
		step = mustParseInt(rangeAndStep[1])
 | 
			
		||||
 | 
			
		||||
		// Special handling: "N/step" means "N-max/step".
 | 
			
		||||
		if singleDigit {
 | 
			
		||||
			end = r.max
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		log.Panicf("Too many slashes: %s", expr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if start < r.min {
 | 
			
		||||
		log.Panicf("Beginning of range (%d) below minimum (%d): %s", start, r.min, expr)
 | 
			
		||||
	}
 | 
			
		||||
	if end > r.max {
 | 
			
		||||
		log.Panicf("End of range (%d) above maximum (%d): %s", end, r.max, expr)
 | 
			
		||||
	}
 | 
			
		||||
	if start > end {
 | 
			
		||||
		log.Panicf("Beginning of range (%d) beyond end of range (%d): %s", start, end, expr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return getBits(start, end, step) | extra_star
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseIntOrName returns the (possibly-named) integer contained in expr.
 | 
			
		||||
func parseIntOrName(expr string, names map[string]uint) uint {
 | 
			
		||||
	if names != nil {
 | 
			
		||||
		if namedInt, ok := names[strings.ToLower(expr)]; ok {
 | 
			
		||||
			return namedInt
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return mustParseInt(expr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// mustParseInt parses the given expression as an int or panics.
 | 
			
		||||
func mustParseInt(expr string) uint {
 | 
			
		||||
	num, err := strconv.Atoi(expr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Panicf("Failed to parse int from %s: %s", expr, err)
 | 
			
		||||
	}
 | 
			
		||||
	if num < 0 {
 | 
			
		||||
		log.Panicf("Negative number (%d) not allowed: %s", num, expr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return uint(num)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getBits sets all bits in the range [min, max], modulo the given step size.
 | 
			
		||||
func getBits(min, max, step uint) uint64 {
 | 
			
		||||
	var bits uint64
 | 
			
		||||
 | 
			
		||||
	// If step is 1, use shifts.
 | 
			
		||||
	if step == 1 {
 | 
			
		||||
		return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Else, use a simple loop.
 | 
			
		||||
	for i := min; i <= max; i += step {
 | 
			
		||||
		bits |= 1 << i
 | 
			
		||||
	}
 | 
			
		||||
	return bits
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// all returns all bits within the given bounds.  (plus the star bit)
 | 
			
		||||
func all(r bounds) uint64 {
 | 
			
		||||
	return getBits(r.min, r.max, 1) | starBit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseDescriptor returns a pre-defined schedule for the expression, or panics
 | 
			
		||||
// if none matches.
 | 
			
		||||
func parseDescriptor(spec string) Schedule {
 | 
			
		||||
	switch spec {
 | 
			
		||||
	case "@yearly", "@annually":
 | 
			
		||||
		return &SpecSchedule{
 | 
			
		||||
			Second: 1 << seconds.min,
 | 
			
		||||
			Minute: 1 << minutes.min,
 | 
			
		||||
			Hour:   1 << hours.min,
 | 
			
		||||
			Dom:    1 << dom.min,
 | 
			
		||||
			Month:  1 << months.min,
 | 
			
		||||
			Dow:    all(dow),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case "@monthly":
 | 
			
		||||
		return &SpecSchedule{
 | 
			
		||||
			Second: 1 << seconds.min,
 | 
			
		||||
			Minute: 1 << minutes.min,
 | 
			
		||||
			Hour:   1 << hours.min,
 | 
			
		||||
			Dom:    1 << dom.min,
 | 
			
		||||
			Month:  all(months),
 | 
			
		||||
			Dow:    all(dow),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case "@weekly":
 | 
			
		||||
		return &SpecSchedule{
 | 
			
		||||
			Second: 1 << seconds.min,
 | 
			
		||||
			Minute: 1 << minutes.min,
 | 
			
		||||
			Hour:   1 << hours.min,
 | 
			
		||||
			Dom:    all(dom),
 | 
			
		||||
			Month:  all(months),
 | 
			
		||||
			Dow:    1 << dow.min,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case "@daily", "@midnight":
 | 
			
		||||
		return &SpecSchedule{
 | 
			
		||||
			Second: 1 << seconds.min,
 | 
			
		||||
			Minute: 1 << minutes.min,
 | 
			
		||||
			Hour:   1 << hours.min,
 | 
			
		||||
			Dom:    all(dom),
 | 
			
		||||
			Month:  all(months),
 | 
			
		||||
			Dow:    all(dow),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case "@hourly":
 | 
			
		||||
		return &SpecSchedule{
 | 
			
		||||
			Second: 1 << seconds.min,
 | 
			
		||||
			Minute: 1 << minutes.min,
 | 
			
		||||
			Hour:   all(hours),
 | 
			
		||||
			Dom:    all(dom),
 | 
			
		||||
			Month:  all(months),
 | 
			
		||||
			Dow:    all(dow),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const every = "@every "
 | 
			
		||||
	if strings.HasPrefix(spec, every) {
 | 
			
		||||
		duration, err := time.ParseDuration(spec[len(every):])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Panicf("Failed to parse duration %s: %s", spec, err)
 | 
			
		||||
		}
 | 
			
		||||
		return Every(duration)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Panicf("Unrecognized descriptor: %s", spec)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										159
									
								
								vendor/github.com/robfig/cron/spec.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								vendor/github.com/robfig/cron/spec.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
package cron
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// SpecSchedule specifies a duty cycle (to the second granularity), based on a
 | 
			
		||||
// traditional crontab specification. It is computed initially and stored as bit sets.
 | 
			
		||||
type SpecSchedule struct {
 | 
			
		||||
	Second, Minute, Hour, Dom, Month, Dow uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// bounds provides a range of acceptable values (plus a map of name to value).
 | 
			
		||||
type bounds struct {
 | 
			
		||||
	min, max uint
 | 
			
		||||
	names    map[string]uint
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The bounds for each field.
 | 
			
		||||
var (
 | 
			
		||||
	seconds = bounds{0, 59, nil}
 | 
			
		||||
	minutes = bounds{0, 59, nil}
 | 
			
		||||
	hours   = bounds{0, 23, nil}
 | 
			
		||||
	dom     = bounds{1, 31, nil}
 | 
			
		||||
	months  = bounds{1, 12, map[string]uint{
 | 
			
		||||
		"jan": 1,
 | 
			
		||||
		"feb": 2,
 | 
			
		||||
		"mar": 3,
 | 
			
		||||
		"apr": 4,
 | 
			
		||||
		"may": 5,
 | 
			
		||||
		"jun": 6,
 | 
			
		||||
		"jul": 7,
 | 
			
		||||
		"aug": 8,
 | 
			
		||||
		"sep": 9,
 | 
			
		||||
		"oct": 10,
 | 
			
		||||
		"nov": 11,
 | 
			
		||||
		"dec": 12,
 | 
			
		||||
	}}
 | 
			
		||||
	dow = bounds{0, 6, map[string]uint{
 | 
			
		||||
		"sun": 0,
 | 
			
		||||
		"mon": 1,
 | 
			
		||||
		"tue": 2,
 | 
			
		||||
		"wed": 3,
 | 
			
		||||
		"thu": 4,
 | 
			
		||||
		"fri": 5,
 | 
			
		||||
		"sat": 6,
 | 
			
		||||
	}}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Set the top bit if a star was included in the expression.
 | 
			
		||||
	starBit = 1 << 63
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Next returns the next time this schedule is activated, greater than the given
 | 
			
		||||
// time.  If no time can be found to satisfy the schedule, return the zero time.
 | 
			
		||||
func (s *SpecSchedule) Next(t time.Time) time.Time {
 | 
			
		||||
	// General approach:
 | 
			
		||||
	// For Month, Day, Hour, Minute, Second:
 | 
			
		||||
	// Check if the time value matches.  If yes, continue to the next field.
 | 
			
		||||
	// If the field doesn't match the schedule, then increment the field until it matches.
 | 
			
		||||
	// While incrementing the field, a wrap-around brings it back to the beginning
 | 
			
		||||
	// of the field list (since it is necessary to re-verify previous field
 | 
			
		||||
	// values)
 | 
			
		||||
 | 
			
		||||
	// Start at the earliest possible time (the upcoming second).
 | 
			
		||||
	t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond)
 | 
			
		||||
 | 
			
		||||
	// This flag indicates whether a field has been incremented.
 | 
			
		||||
	added := false
 | 
			
		||||
 | 
			
		||||
	// If no time is found within five years, return zero.
 | 
			
		||||
	yearLimit := t.Year() + 5
 | 
			
		||||
 | 
			
		||||
WRAP:
 | 
			
		||||
	if t.Year() > yearLimit {
 | 
			
		||||
		return time.Time{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Find the first applicable month.
 | 
			
		||||
	// If it's this month, then do nothing.
 | 
			
		||||
	for 1<<uint(t.Month())&s.Month == 0 {
 | 
			
		||||
		// If we have to add a month, reset the other parts to 0.
 | 
			
		||||
		if !added {
 | 
			
		||||
			added = true
 | 
			
		||||
			// Otherwise, set the date at the beginning (since the current time is irrelevant).
 | 
			
		||||
			t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
 | 
			
		||||
		}
 | 
			
		||||
		t = t.AddDate(0, 1, 0)
 | 
			
		||||
 | 
			
		||||
		// Wrapped around.
 | 
			
		||||
		if t.Month() == time.January {
 | 
			
		||||
			goto WRAP
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Now get a day in that month.
 | 
			
		||||
	for !dayMatches(s, t) {
 | 
			
		||||
		if !added {
 | 
			
		||||
			added = true
 | 
			
		||||
			t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
 | 
			
		||||
		}
 | 
			
		||||
		t = t.AddDate(0, 0, 1)
 | 
			
		||||
 | 
			
		||||
		if t.Day() == 1 {
 | 
			
		||||
			goto WRAP
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for 1<<uint(t.Hour())&s.Hour == 0 {
 | 
			
		||||
		if !added {
 | 
			
		||||
			added = true
 | 
			
		||||
			t = t.Truncate(time.Hour)
 | 
			
		||||
		}
 | 
			
		||||
		t = t.Add(1 * time.Hour)
 | 
			
		||||
 | 
			
		||||
		if t.Hour() == 0 {
 | 
			
		||||
			goto WRAP
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for 1<<uint(t.Minute())&s.Minute == 0 {
 | 
			
		||||
		if !added {
 | 
			
		||||
			added = true
 | 
			
		||||
			t = t.Truncate(time.Minute)
 | 
			
		||||
		}
 | 
			
		||||
		t = t.Add(1 * time.Minute)
 | 
			
		||||
 | 
			
		||||
		if t.Minute() == 0 {
 | 
			
		||||
			goto WRAP
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for 1<<uint(t.Second())&s.Second == 0 {
 | 
			
		||||
		if !added {
 | 
			
		||||
			added = true
 | 
			
		||||
			t = t.Truncate(time.Second)
 | 
			
		||||
		}
 | 
			
		||||
		t = t.Add(1 * time.Second)
 | 
			
		||||
 | 
			
		||||
		if t.Second() == 0 {
 | 
			
		||||
			goto WRAP
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// dayMatches returns true if the schedule's day-of-week and day-of-month
 | 
			
		||||
// restrictions are satisfied by the given time.
 | 
			
		||||
func dayMatches(s *SpecSchedule, t time.Time) bool {
 | 
			
		||||
	var (
 | 
			
		||||
		domMatch bool = 1<<uint(t.Day())&s.Dom > 0
 | 
			
		||||
		dowMatch bool = 1<<uint(t.Weekday())&s.Dow > 0
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if s.Dom&starBit > 0 || s.Dow&starBit > 0 {
 | 
			
		||||
		return domMatch && dowMatch
 | 
			
		||||
	}
 | 
			
		||||
	return domMatch || dowMatch
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user