forked from webdevops/go-crond
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.go
151 lines (123 loc) · 3.3 KB
/
parser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"bufio"
"fmt"
"os"
"regexp"
"strings"
log "github.com/sirupsen/logrus"
)
const (
ENV_LINE = `^(\S+)=(\S+)\s*$`
// ----spec------------------------------------ --user-- -cmd-
CRONJOB_SYSTEM = `^\s*([^@\s]+\s+\S+\s+\S+\s+\S+\s+\S+|@every\s+\S+)\s+([^\s]+)\s+(.+)$`
// ----spec------------------------------------ -cmd-
CRONJOB_USER = `^\s*([^@\s]+\s+\S+\s+\S+\s+\S+\s+\S+|@every\s+\S+)\s+(.+)$`
DEFAULT_SHELL = "sh"
)
var (
envLineRegex = regexp.MustCompile(ENV_LINE)
cronjobSystemRegex = regexp.MustCompile(CRONJOB_SYSTEM)
cronjobUserRegex = regexp.MustCompile(CRONJOB_USER)
)
type CrontabEntry struct {
Spec string
User string
Command string
Env []string
Shell string
CrontabPath string
}
type Parser struct {
cronLineRegex *regexp.Regexp
cronjobUsername string
path string
}
// Create new crontab parser (user crontab without user specification)
func NewCronjobUserParser(path string, username string) (*Parser, error) {
p := &Parser{
cronLineRegex: cronjobUserRegex,
path: path,
cronjobUsername: username,
}
return p, nil
}
// Create new crontab parser (crontab with user specification)
func NewCronjobSystemParser(path string) (*Parser, error) {
p := &Parser{
cronLineRegex: cronjobSystemRegex,
path: path,
cronjobUsername: CRONTAB_TYPE_SYSTEM,
}
return p, nil
}
// Parse crontab
func (p *Parser) Parse() []CrontabEntry {
entries := p.parseLines()
return entries
}
// Parse lines from crontab
func (p *Parser) parseLines() []CrontabEntry {
var (
entries []CrontabEntry
crontabSpec string
crontabUser string
crontabCommand string
environment []string
)
reader, err := os.Open(p.path)
if err != nil {
log.Fatalf("crontab path: %v err:%v", p.path, err)
}
defer reader.Close()
shell := DEFAULT_SHELL
specCleanupRegexp := regexp.MustCompile(`\s+`)
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
// comment line
if strings.HasPrefix(line, "#") {
continue
}
// environment line
if envLineRegex.MatchString(line) {
m := envLineRegex.FindStringSubmatch(line)
envName := strings.TrimSpace(m[1])
envValue := strings.TrimSpace(m[2])
if envName == "SHELL" {
// custom shell for command
shell = envValue
} else {
// normal environment variable
environment = append(environment, fmt.Sprintf("%s=%s", envName, envValue))
}
}
// cronjob line
if p.cronLineRegex.MatchString(line) {
m := p.cronLineRegex.FindStringSubmatch(line)
if p.cronjobUsername == CRONTAB_TYPE_SYSTEM {
crontabSpec = strings.TrimSpace(m[1])
crontabUser = strings.TrimSpace(m[2])
crontabCommand = strings.TrimSpace(m[3])
} else {
crontabSpec = strings.TrimSpace(m[1])
crontabUser = p.cronjobUsername
crontabCommand = strings.TrimSpace(m[2])
}
// shrink white spaces for better handling
crontabSpec = specCleanupRegexp.ReplaceAllString(crontabSpec, " ")
entries = append(
entries,
CrontabEntry{
Spec: crontabSpec,
User: crontabUser,
Command: crontabCommand,
Env: environment,
Shell: shell,
CrontabPath: p.path,
},
)
}
}
return entries
}