forked from fatiherikli/nginxparser
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nginxparser.py
130 lines (103 loc) · 3.63 KB
/
nginxparser.py
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
import string
from pyparsing import (
Literal, White, Word, alphanums, CharsNotIn, Forward, Group, SkipTo,
Optional, OneOrMore, ZeroOrMore, pythonStyleComment)
class NginxParser(object):
"""
A class that parses nginx configuration with pyparsing
"""
# constants
left_bracket = Literal("{").suppress()
right_bracket = Literal("}").suppress()
semicolon = Literal(";").suppress()
space = White().suppress()
key = Word(alphanums + "_/")
value = CharsNotIn("{};")
value2 = CharsNotIn(";")
location = CharsNotIn("{};," + string.whitespace)
ifword = Literal("if")
setword = Literal("set")
# modifier for location uri [ = | ~ | ~* | ^~ ]
modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~")
# rules
assignment = (key + Optional(space + value) + semicolon)
setblock = (setword + OneOrMore(space + value2) + semicolon)
block = Forward()
ifblock = Forward()
subblock = Forward()
ifblock << (
Group(ifword + Optional(space) + Optional(value) + SkipTo('{'))
+ left_bracket
+ Group(subblock)
+ right_bracket)
subblock << ZeroOrMore(
Group(assignment) | block | Group(ifblock) | setblock
)
block << Group(
Group(key + Optional(space + modifier) + Optional(space + location))
+ left_bracket
+ Group(subblock)
+ right_bracket
)
script = OneOrMore(Group(assignment) | block).ignore(pythonStyleComment)
def __init__(self, source):
self.source = source
def parse(self):
"""
Returns the parsed tree.
"""
return self.script.parseString(self.source)
def as_list(self):
"""
Returns the list of tree.
"""
return self.parse().asList()
class NginxDumper(object):
"""
A class that dumps nginx configuration from the provided tree.
"""
def __init__(self, blocks, indentation=4):
self.blocks = blocks
self.indentation = indentation
def __iter__(self, blocks=None, current_indent=0, spacer=' '):
"""
Iterates the dumped nginx content.
"""
blocks = blocks or self.blocks
for key, values in blocks:
if current_indent:
yield spacer
indentation = spacer * current_indent
if isinstance(key, list):
yield indentation + spacer.join(key) + ' {'
for parameter in values:
if isinstance(parameter[0], list):
dumped = self.__iter__(
[parameter],
current_indent + self.indentation)
for line in dumped:
yield line
else:
dumped = spacer.join(parameter) + ';'
yield spacer * (
current_indent + self.indentation) + dumped
yield indentation + '}'
else:
yield spacer * current_indent + key + spacer + values + ';'
def as_string(self):
return '\n'.join(self)
def to_file(self, out):
for line in self:
out.write(line+"\n")
out.close()
return out
# Shortcut functions to respect Python's serialization interface
# (like pyyaml, picker or json)
def loads(source):
return NginxParser(source).as_list()
def load(_file):
return loads(_file.read())
def dumps(blocks, indentation=4):
return NginxDumper(blocks, indentation).as_string()
def dump(blocks, _file, indentation=4):
return NginxDumper(blocks, indentation).to_file(_file)