11package main
22
33import (
4+ "path"
45 "path/filepath"
56 "strings"
67 "regexp"
8+ "time"
9+ "os"
10+ "bufio"
11+ "log"
12+ "github.com/robfig/cron"
13+ "fmt"
714)
815
916type Job struct {
1017 Filepath string
1118 Spec string
19+ Timezone * time.Location
1220 Name string
21+ Timeout time.Duration
22+ Enabled bool
23+ Errors []string
24+ UpdateTime time.Time
1325}
1426
1527var cronSpecRegex ,_ = regexp .Compile (`\s*($|#|\w+\s*=|(x|\*|(?:[0-5]?\d)(?:(?:-|%|\,)(?:[0-5]?\d))?(?:,(?:[0-5]?\d)(?:(?:-|%|\,)(?:[0-5]?\d))?)*)\s+(x|\*|(?:[0-5]?\d)(?:(?:-|%|\,)(?:[0-5]?\d))?(?:,(?:[0-5]?\d)(?:(?:-|%|\,)(?:[0-5]?\d))?)*)\s+(x|\*|(?:[01]?\d|2[0-3])(?:(?:-|%|\,)(?:[01]?\d|2[0-3]))?(?:,(?:[01]?\d|2[0-3])(?:(?:-|%|\,)(?:[01]?\d|2[0-3]))?)*)\s+(x|\*|(?:0?[1-9]|[12]\d|3[01])(?:(?:-|%|\,)(?:0?[1-9]|[12]\d|3[01]))?(?:,(?:0?[1-9]|[12]\d|3[01])(?:(?:-|%|\,)(?:0?[1-9]|[12]\d|3[01]))?)*)\s+(x|\*|(?:[1-9]|1[012])(?:(?:-|%|\,)(?:[1-9]|1[012]))?(?:L|W)?(?:,(?:[1-9]|1[012])(?:(?:-|%|\,)(?:[1-9]|1[012]))?(?:L|W)?)*|x|\*|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*)\s+(x|\*|(?:[0-6])(?:(?:-|%|\,|#)(?:[0-6]))?(?:L)?(?:,(?:[0-6])(?:(?:-|%|\,|#)(?:[0-6]))?(?:L)?)*|x|\*|(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?(?:,(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?)*)(|\s)+(x|\*|(?:|\d{4})(?:(?:-|%|\,)(?:|\d{4}))?(?:,(?:|\d{4})(?:(?:-|%|\,)(?:|\d{4}))?)*)) (.*)\.godoit` )
28+ var noTimeout = time .Second * 0
29+ var GodoitFileSuffix = ".godoit"
30+ var godoitCommentPrefix = "#:godoit "
31+
32+
33+ func ParseJobFile (directory , filename string ) * Job {
34+ jobPath := path .Join (directory , filename )
35+ var cronspec string
36+ var name string
37+ enabled :=
38+ ! strings .HasPrefix (filename , "--" ) &&
39+ ! strings .HasPrefix (filename , "#" )
1640
17- func ParseJobFile (path , filename string ) * Job {
18- // Return commented out files
19- if strings .HasPrefix (filename , "--" ) {
20- return nil
21- }
2241 if result := cronSpecRegex .FindStringSubmatch (filename ); result != nil {
23- cronspec : = strings .Replace (result [1 ], "x" , "*" , - 1 )
42+ cronspec = strings .Replace (result [1 ], "x" , "*" , - 1 )
2443 cronspec = strings .Replace (cronspec , "%" , "/" , - 1 )
25- return & Job {filepath .Join (path , filename ), cronspec , strings .TrimSpace (result [10 ])}
44+ name = strings .TrimSpace (result [10 ])
45+ } else if strings .HasSuffix (filename , GodoitFileSuffix ) {
46+ name = strings .TrimSuffix (filename , GodoitFileSuffix )
2647 } else {
2748 return nil
2849 }
50+
51+ cronspec , timeout , timezone , errors , updateTime := parseJobParameters (jobPath , cronspec )
52+
53+ if cronspec == "" {
54+ errors = append (errors , "Missing cronspec" )
55+ }
56+
57+ if len (errors ) > 0 {
58+ enabled = false
59+ log .Printf ("Errors parsing job %s: %v" , jobPath , errors )
60+ }
61+
62+ return & Job {
63+ filepath .Join (directory , filename ),
64+ cronspec ,
65+ timezone ,
66+ name ,
67+ timeout ,
68+ enabled ,
69+ errors ,
70+ updateTime }
71+ }
72+
73+ func parseJobParameters (jobPath , cronspec string ) (string , time.Duration , * time.Location , []string , time.Time ) {
74+ timeout := 0 * time .Second
75+ timezone := time .UTC
76+ var updateTime time.Time
77+ errors := make ([]string ,0 ,10 )
78+
79+ if file , err := os .Open (jobPath ); err == nil {
80+ defer file .Close ()
81+ if info , err := file .Stat () ; err == nil {
82+ updateTime = info .ModTime ()
83+ }
84+
85+ // create a new scanner and read the file line by line
86+ scanner := bufio .NewScanner (file )
87+ i := 0
88+ for scanner .Scan () {
89+ // Only scan start of file for params...
90+ i ++
91+ if i > 10 {
92+ break
93+ }
94+
95+ line := scanner .Text ()
96+ if strings .HasPrefix (line , godoitCommentPrefix ) {
97+ line = strings .TrimPrefix (line , godoitCommentPrefix )
98+ line = strings .TrimSpace (line )
99+ parts := strings .SplitN (line ," " ,2 )
100+ if len (parts ) == 2 {
101+ param := parts [0 ]
102+ value := parts [1 ]
103+ if param == "cronspec" {
104+ if cronspec != "" {
105+ errors = append (errors , "Cronspec in filename and as comment" )
106+ }
107+ if _ , err := cron .Parse (value ); err == nil {
108+ cronspec = value
109+ } else {
110+ errors = append (errors , fmt .Sprintf ("Invalid cronspec: '%s'" , value ))
111+ }
112+ } else if param == "timeout" {
113+ if d , err := time .ParseDuration (value ); err == nil {
114+ timeout = d
115+ } else {
116+ errors = append (errors , fmt .Sprintf ("Invalid timeout: '%s'" , value ))
117+ }
118+ } else if param == "timezone" {
119+ if l , err := time .LoadLocation (value ); err == nil {
120+ timezone = l
121+ } else {
122+ errors = append (errors , fmt .Sprintf ("Invalid timezone: '%s'" , value ))
123+ }
124+ }
125+
126+ } else {
127+ errors = append (errors , fmt .Sprintf ("Invalid parameter '%s'" , line ))
128+ }
129+ }
130+ }
131+ } else {
132+ errors = append (errors , "Unable to open file to parse parameters" )
133+ }
134+ return cronspec , timeout , timezone , errors , updateTime
29135}
0 commit comments