Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
aabf86ab
Commit
aabf86ab
authored
May 11, 2016
by
Maciej Szulik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding github.com/robfig/cron for cron parsing
parent
5c9b4bfe
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
849 additions
and
0 deletions
+849
-0
Godeps.json
Godeps/Godeps.json
+4
-0
LICENSES
Godeps/LICENSES
+26
-0
.gitignore
vendor/github.com/robfig/cron/.gitignore
+22
-0
.travis.yml
vendor/github.com/robfig/cron/.travis.yml
+1
-0
LICENSE
vendor/github.com/robfig/cron/LICENSE
+21
-0
README.md
vendor/github.com/robfig/cron/README.md
+2
-0
constantdelay.go
vendor/github.com/robfig/cron/constantdelay.go
+27
-0
cron.go
vendor/github.com/robfig/cron/cron.go
+227
-0
doc.go
vendor/github.com/robfig/cron/doc.go
+129
-0
parser.go
vendor/github.com/robfig/cron/parser.go
+231
-0
spec.go
vendor/github.com/robfig/cron/spec.go
+159
-0
No files found.
Godeps/Godeps.json
View file @
aabf86ab
...
...
@@ -1761,6 +1761,10 @@
"Rev"
:
"8992d7483a06748dea706e4716d042a4a9e73918"
},
{
"ImportPath"
:
"github.com/robfig/cron"
,
"Rev"
:
"0f39cf7ebc65a602f45692f9894bd6a193faf8fa"
},
{
"ImportPath"
:
"github.com/russross/blackfriday"
,
"Comment"
:
"v1.2-42-g77efab5"
,
"Rev"
:
"77efab57b2f74dd3f9051c79752b2e8995c8b789"
...
...
Godeps/LICENSES
View file @
aabf86ab
...
...
@@ -59126,6 +59126,32 @@ specific language governing permissions and limitations under the License.
================================================================================
= 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: =
Blackfriday is distributed under the Simplified BSD License:
vendor/github.com/robfig/cron/.gitignore
0 → 100644
View file @
aabf86ab
# 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
vendor/github.com/robfig/cron/.travis.yml
0 → 100644
View file @
aabf86ab
language
:
go
vendor/github.com/robfig/cron/LICENSE
0 → 100644
View file @
aabf86ab
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/robfig/cron/README.md
0 → 100644
View file @
aabf86ab
[

](http://godoc.org/github.com/robfig/cron)
[

](https://travis-ci.org/robfig/cron)
vendor/github.com/robfig/cron/constantdelay.go
0 → 100644
View file @
aabf86ab
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
)
}
vendor/github.com/robfig/cron/cron.go
0 → 100644
View file @
aabf86ab
// 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
}
vendor/github.com/robfig/cron/doc.go
0 → 100644
View file @
aabf86ab
/*
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
vendor/github.com/robfig/cron/parser.go
0 → 100644
View file @
aabf86ab
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
}
vendor/github.com/robfig/cron/spec.go
0 → 100644
View file @
aabf86ab
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
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment