0
# Low-level Configuration Parser
1
2
Low-level nginx configuration parser based on pyparsing that handles the complete nginx configuration syntax. Provides parsing, modification, and serialization capabilities for nginx configuration files.
3
4
## Capabilities
5
6
### Raw Configuration Parsing
7
8
Parse nginx configuration files into structured data with complete syntax support.
9
10
```python { .api }
11
class RawNginxParser:
12
"""Raw nginx configuration parser using pyparsing.
13
14
Args:
15
source: Nginx configuration source string
16
17
Attributes:
18
source: str - Configuration source content
19
"""
20
21
def __init__(self, source: str) -> None:
22
"""Initialize parser with configuration source."""
23
24
def parse(self) -> ParseResults:
25
"""Parse nginx configuration.
26
27
Returns:
28
Parsed configuration tree as ParseResults
29
"""
30
31
def as_list(self) -> list[Any]:
32
"""Convert parsed tree to list representation.
33
34
Returns:
35
Parsed tree as nested list structure
36
"""
37
```
38
39
### Configuration Serialization
40
41
Convert parsed configuration back to nginx configuration format.
42
43
```python { .api }
44
class RawNginxDumper:
45
"""Dumps nginx configuration from parsed tree.
46
47
Args:
48
blocks: Parsed configuration blocks
49
50
Attributes:
51
blocks: list[Any] - Configuration blocks to dump
52
"""
53
54
def __init__(self, blocks: list[Any]) -> None:
55
"""Initialize dumper with configuration blocks."""
56
57
def __iter__(self, blocks: Optional[list[Any]] = None) -> Iterator[str]:
58
"""Iterate over dumped nginx content.
59
60
Args:
61
blocks: Optional blocks to iterate (uses self.blocks if None)
62
63
Yields:
64
Configuration content strings
65
"""
66
67
def __str__(self) -> str:
68
"""Convert parsed blocks to nginx configuration string.
69
70
Returns:
71
Complete nginx configuration as string
72
"""
73
```
74
75
### Whitespace-Aware List Handling
76
77
Special list implementation that manages whitespace in nginx configuration.
78
79
```python { .api }
80
class UnspacedList(list[Any]):
81
"""List wrapper that makes whitespace entries invisible.
82
83
Maintains both spaced and unspaced representations of configuration
84
data while preserving original formatting and structure.
85
86
Args:
87
list_source: Source list or iterable to wrap
88
89
Attributes:
90
spaced: list[Any] - Original list with whitespace preserved
91
dirty: bool - Whether list has been modified
92
"""
93
94
def __init__(self, list_source: Iterable[Any]) -> None:
95
"""Initialize with source list, removing whitespace from main list."""
96
```
97
98
### List Modification Operations
99
100
Modified list operations that maintain whitespace structure.
101
102
```python { .api }
103
def insert(self, i: SupportsIndex, x: Any) -> None:
104
"""Insert object before index.
105
106
Args:
107
i: Index position for insertion
108
x: Object to insert
109
"""
110
111
def append(self, x: Any) -> None:
112
"""Append object to end of list.
113
114
Args:
115
x: Object to append
116
"""
117
118
def extend(self, x: Any) -> None:
119
"""Extend list by appending elements from iterable.
120
121
Args:
122
x: Iterable to extend with
123
"""
124
125
def __add__(self, other: list[Any]) -> "UnspacedList":
126
"""Add lists together.
127
128
Args:
129
other: List to add
130
131
Returns:
132
New UnspacedList with combined contents
133
"""
134
```
135
136
### High-Level Parser Functions
137
138
Convenience functions for parsing and dumping nginx configurations.
139
140
```python { .api }
141
def load(file_: IO[Any]) -> UnspacedList:
142
"""Parse nginx configuration from file object.
143
144
Args:
145
file_: File-like object to parse from
146
147
Returns:
148
Parsed configuration as UnspacedList
149
150
Raises:
151
ParseException: If configuration syntax is invalid
152
"""
153
154
def loads(source: str) -> UnspacedList:
155
"""Parse nginx configuration from string.
156
157
Args:
158
source: Configuration string
159
160
Returns:
161
Parsed configuration as UnspacedList
162
163
Raises:
164
ParseException: If configuration syntax is invalid
165
"""
166
167
def dump(parsed_obj: UnspacedList, output: IO[str]) -> None:
168
"""Write parsed configuration to file.
169
170
Args:
171
parsed_obj: Parsed configuration object
172
output: File-like object for output
173
"""
174
175
def dumps(parsed_obj: UnspacedList) -> str:
176
"""Convert parsed configuration to string.
177
178
Args:
179
parsed_obj: Parsed configuration object
180
181
Returns:
182
Configuration as nginx format string
183
"""
184
```
185
186
### Utility Functions
187
188
Helper functions for working with configuration elements.
189
190
```python { .api }
191
def spacey(x: Any) -> bool:
192
"""Check if x is empty string or whitespace.
193
194
Args:
195
x: Object to check
196
197
Returns:
198
True if x is whitespace or empty string
199
"""
200
```
201
202
## Internal Implementation Details
203
204
The parser uses pyparsing to define nginx configuration grammar:
205
206
```python { .api }
207
# Grammar components (read-only attributes)
208
space: Optional[White] # Optional whitespace
209
required_space: White # Required whitespace
210
left_bracket: Literal # Opening brace
211
right_bracket: Literal # Closing brace with space
212
semicolon: Literal # Semicolon
213
dquoted: QuotedString # Double-quoted strings
214
squoted: QuotedString # Single-quoted strings
215
quoted: Union # Any quoted string
216
token: Union # Configuration tokens
217
assignment: ParseElement # Directive assignments
218
comment: ParseElement # Comment lines
219
block: Forward # Configuration blocks
220
contents: Group # Block contents
221
script: ZeroOrMore # Complete configuration
222
```
223
224
## Usage Examples
225
226
### Basic Configuration Parsing
227
228
```python
229
from certbot_nginx._internal import nginxparser
230
231
# Parse configuration from file
232
with open('/etc/nginx/nginx.conf', 'r') as f:
233
config = nginxparser.load(f)
234
print(f"Parsed {len(config)} top-level blocks")
235
236
# Parse configuration from string
237
config_str = """
238
server {
239
listen 80;
240
server_name example.com;
241
location / {
242
return 200 "Hello World";
243
}
244
}
245
"""
246
parsed = nginxparser.loads(config_str)
247
print(f"Parsed: {parsed}")
248
```
249
250
### Configuration Modification
251
252
```python
253
# Load and modify configuration
254
with open('/etc/nginx/sites-available/default', 'r') as f:
255
config = nginxparser.load(f)
256
257
# Find server block
258
for block in config:
259
if isinstance(block, list) and block[0] == ['server']:
260
server_block = block[1]
261
262
# Add new directive
263
new_directive = ['listen', '443', 'ssl']
264
server_block.append(new_directive)
265
266
# Add SSL certificate directives
267
ssl_cert = ['ssl_certificate', '/path/to/cert.pem']
268
ssl_key = ['ssl_certificate_key', '/path/to/key.pem']
269
server_block.extend([ssl_cert, ssl_key])
270
271
# Write back to file
272
with open('/etc/nginx/sites-available/default', 'w') as f:
273
nginxparser.dump(config, f)
274
```
275
276
### Working with UnspacedList
277
278
```python
279
from certbot_nginx._internal.nginxparser import UnspacedList
280
281
# Create UnspacedList from regular list
282
original = [' ', 'server', ' ', '{', '\n', ' ', 'listen', ' ', '80', ';', '\n', '}']
283
unspaced = UnspacedList(original)
284
285
print(f"Original length: {len(original)}") # Shows all elements including whitespace
286
print(f"Unspaced length: {len(unspaced)}") # Shows only non-whitespace elements
287
print(f"Unspaced content: {unspaced}") # ['server', '{', 'listen', '80', ';', '}']
288
289
# Modifications maintain spacing
290
unspaced.append(['server_name', 'example.com'])
291
print(f"Modified: {unspaced}")
292
293
# Access original spaced version
294
print(f"Spaced version: {unspaced.spaced}")
295
```
296
297
### Advanced Parsing with Error Handling
298
299
```python
300
import pyparsing
301
302
try:
303
with open('/etc/nginx/nginx.conf', 'r') as f:
304
config = nginxparser.load(f)
305
306
# Process configuration blocks
307
for block in config:
308
if isinstance(block, list) and len(block) >= 2:
309
if block[0] == ['http']:
310
print("Found HTTP block")
311
http_contents = block[1]
312
313
# Look for server blocks within HTTP
314
for item in http_contents:
315
if isinstance(item, list) and item[0] == ['server']:
316
print(f"Found server block with {len(item[1])} directives")
317
318
except FileNotFoundError:
319
print("Configuration file not found")
320
except pyparsing.ParseException as e:
321
print(f"Parse error: {e}")
322
except Exception as e:
323
print(f"Error processing configuration: {e}")
324
```
325
326
### Configuration Generation
327
328
```python
329
# Build configuration programmatically
330
config = UnspacedList([])
331
332
# Create server block
333
server_block = UnspacedList([
334
['listen', '80'],
335
['server_name', 'example.com'],
336
['location', '/', [
337
['return', '200', '"Hello World"']
338
]]
339
])
340
341
# Add to main configuration
342
config.append(['server', server_block])
343
344
# Convert to string
345
config_str = nginxparser.dumps(config)
346
print(config_str)
347
```
348
349
This produces nginx configuration like:
350
```nginx
351
server {
352
listen 80;
353
server_name example.com;
354
location / {
355
return 200 "Hello World";
356
}
357
}
358
```