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
152
153
154
155
156
157
158
159
160
|
# Parse a Steuermann Spec file
#
# This is an exyapps grammer in specfile.exy
from . import nodes
%%
parser specfile:
ignore: "[ \r\t\n]+"
ignore: "#.*\n"
token END: "$"
token HOSTGROUP: "HOSTGROUP"
token IF: "IF"
token IFNOT: "IFNOT"
token TABLE: "TABLE"
token HOST : "HOST"
token CMD: "CMD"
token OPT: "OPT"
token AFTER: "AFTER"
token RUN: "RUN"
token LOCAL: "LOCAL"
token IMPORT: "IMPORT"
token RESOURCE: "RESOURCE"
token DEBUG: "DEBUG"
token name: "[a-zA-Z0-9_.-]+"
token STAR: "\*"
token cmdname: "[a-zA-Z0-9_.-]+"
token tablename: "[a-zA-Z0-9_.-]+"
token wildname: "[@]{0,1}[*?a-zA-Z0-9_.-]+"
token string: '"[^"]*"'
token SLASH: "/"
token COLON: ":"
token hostgroup: "@[a-zA-Z0-9_.-]+"
token number: "[0-9]+"
token RES_ALL: "all"
token RES_AVAILABLE: "available"
# watch carefully: none of the keywords are "END" on a line by themselves
token CONDITIONS: 'CONDITIONS[^"]*\n[\s]*END[ \t]*\n'
##
# This is the whole file
rule start: table_list "$" {{ return table_list }}
##
#
rule table_list: table_section +
##
#
rule table_section:
DEBUG string {{ print("-->debug: %s"%string) }}
| hostgroup_def
| CONDITIONS {{ nodes.declare_conditions( CONDITIONS, self._scanner.filename ) }}
| TABLE tablename {{ table_name = tablename }} HOST {{ hostlist = [ ] }}
(
name {{ hostlist.append(name) }}
| hostgroup {{ hostlist = hostlist + nodes.get_hostgroup( hostgroup ) }}
)+
cond_command<<tablename,hostlist>> +
| IMPORT string {{ self.data.import_list.append( string[1:-1] ) }}
##
#
rule hostgroup_def :
HOSTGROUP hostgroup {{ nodes.define_hostgroup( hostgroup) }}
( hostgroup_front<<hostgroup>> hostgroup_back<<hostgroup,hostgroup_front>> )+
##
#
rule hostgroup_front<<hg>> :
IF name
{{ return nodes.check_condition(name, self._scanner.filename ) }}
| IFNOT name
{{ return not nodes.check_condition(name, self._scanner.filename ) }}
| {{ return True }}
##
#
rule hostgroup_back<<hg,accept_nodes>> :
COLON (
name {{ if accept_nodes : nodes.add_hostgroup( hg, name ) }}
| hostgroup {{ if accept_nodes : nodes.add_hostgroup( hg, hostgroup ) }}
)*
##
#
rule cond_command<<table_name,hostlist>> :
IF name COLON command
{{ if nodes.check_condition(name, self._scanner.filename ) : self.data.add_command_list( table_name, hostlist, [ command ] ) }}
| IFNOT name COLON command
{{ if not nodes.check_condition(name, self._scanner.filename ) : self.data.add_command_list( table_name, hostlist, [ command ] ) }}
| command
{{ self.data.add_command_list( table_name, hostlist, [ command ] ) }}
##
# a single command, including any number of AFTER clauses
rule command:
CMD
{{ cmd_pos = self._scanner.get_pos() }}
{{ script_type = 'l' }}
{{ resources = { 'cpu' : 1 } }}
cmdname
{{ cmd_name=cmdname; script=cmdname; x_after_clause = [ ] }}
[
RUN string
{{ script = string[1:-1]; script_type='r' }}
|
LOCAL string
{{ script = string[1:-1]; script_type='l' }}
]
(
{{ after_pos = self._scanner.get_pos() }}
[
RESOURCE resource_defs
{{ resources.update(resource_defs) }}
]
AFTER optword after_spec
{{ x_after_clause.append( (after_spec, optword, after_pos) ) }}
)*
{{ return ( cmd_name, script, script_type, x_after_clause, cmd_pos, resources ) }}
##
#
rule resource_defs:
{{ rl = { } }}
(
name
"="
(
number
{{ ans = int(number) }}
| RES_ALL
{{ ans = 'all' }}
| RES_AVAILABLE
{{ ans = 'available' }}
)
{{ rl[name] = ans }}
) *
{{ print(rl) ; return rl }}
##
# in the AFTER clause, you can say OPT to mean the node is optional (not an error if it does not exist)
rule optword:
OPT {{ return 0 }}
| {{ return 1 }}
##
rule after_spec:
wildname {{ rval = wildname }}
[ COLON wildname {{ rval = rval + ':' + wildname }} ]
[ SLASH wildname {{ rval = rval + '/' + wildname }} ]
{{ return rval }}
%%
|