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
|
from reconfigure.nodes import *
from reconfigure.parsers import BaseParser
import re
class NginxParser (BaseParser):
"""
A parser for nginx configs
"""
tokens = [
(r"[\w_]+\s*?.*?{", lambda s, t: ('section_start', t)),
(r"[\w_]+?.+?;", lambda s, t: ('option', t)),
(r"\s", lambda s, t: 'whitespace'),
(r"$^", lambda s, t: 'newline'),
(r"\#.*?\n", lambda s, t: ('comment', t)),
(r"\}", lambda s, t: 'section_end'),
]
token_comment = '#'
token_section_end = '}'
def parse(self, content):
scanner = re.Scanner(self.tokens)
tokens, remainder = scanner.scan(' '.join(filter(None, content.split(' '))))
if remainder:
raise Exception('Invalid tokens: %s' % remainder)
node = RootNode()
node.parameter = None
node_stack = []
next_comment = None
while len(tokens) > 0:
token = tokens[0]
tokens = tokens[1:]
if token in ['whitespace', 'newline']:
continue
if token == 'section_end':
node = node_stack.pop()
if token[0] == 'comment':
if not next_comment:
next_comment = ''
else:
next_comment += '\n'
next_comment += token[1].strip('#/*').strip()
if token[0] == 'option':
if ' ' in token[1] and not token[1][0] in ['"', "'"]:
k, v = token[1].split(None, 1)
else:
v = token[1]
k = ''
prop = PropertyNode(k.strip(), v[:-1].strip())
prop.comment = next_comment
next_comment = None
node.children.append(prop)
if token[0] == 'section_start':
line = token[1][:-1].strip().split(None, 1) + [None]
section = Node(line[0])
section.parameter = line[1]
section.comment = next_comment
next_comment = None
node_stack += [node]
node.children.append(section)
node = section
return node
def stringify(self, tree):
return ''.join(self.stringify_rec(node) for node in tree.children)
def stringify_rec(self, node):
if isinstance(node, PropertyNode):
if node.name:
s = '%s %s;\n' % (node.name, node.value)
else:
s = '%s;\n' % (node.value)
elif isinstance(node, IncludeNode):
s = 'include %s;\n' % (node.files)
else:
result = '\n%s %s {\n' % (node.name, node.parameter or '')
for child in node.children:
result += '\n'.join('\t' + x for x in self.stringify_rec(child).splitlines()) + '\n'
result += self.token_section_end + '\n'
s = result
if node.comment:
s = ''.join(self.token_comment + ' %s\n' % l for l in node.comment.splitlines()) + s
return s
|