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
|
# Parse a Steuermann Spec file
#
# This is an exyapps grammer in specfile.exy
import nodes
%%
parser specfile:
ignore: "[ \r\t\n]+"
ignore: "#.*\n"
token END: "$"
token HOSTGROUP: "HOSTGROUP"
token IF: "IF"
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 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_.-]+"
# watch carefully: none of the keywords are "END" on a line by themselves
token CONDITIONS: 'CONDITIONS[^"]*\n[\s]*END[ \t]*\n'
rule start: table_list END {{ 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 ) }}
)+
command_list
# command_list is a list of (command, pos) where command is the text from the file and pos is the location in the file
{{ self.data.add_command_list( table_name, hostlist, command_list ) }}
| IMPORT string {{ self.data.import_list.append( string[1:-1] ) }}
##
rule hostgroup_def :
HOSTGROUP hostgroup {{ nodes.define_hostgroup( hostgroup) }}
( hostgroup_if<<hostgroup>> )+
rule hostgroup_if<<hg>> :
IF name
{{ accept_nodes = nodes.check_condition(name, self._scanner.filename ) }}
COLON (
name {{ if accept_nodes : nodes.add_hostgroup( hg, name ) }}
)+
rule command_list:
# one or more commands, appended together into a list
{{ cmlist = [ ] }}
command {{ cmlist.append( command ) }}
[
command_list {{ cmlist += command_list }}
]
{{ return cmlist }}
| {{ return [ ] }}
rule command:
# a single command, including any number of AFTER clauses
CMD {{ cmd_pos = self._scanner.get_pos() }}
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() }}
AFTER optword after_spec {{ x_after_clause.append( (after_spec, optword, after_pos) ) }}
)*
{{ return ( cmd_name, script, script_type, x_after_clause, cmd_pos ) }}
# 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 }}
%%
|