You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
9.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# vim: fileencoding=utf-8
#
# ToDo: написать счетчик скобок для финальной оценки корректности
# документа.
#
from .base_format import BaseFormat
from collections import OrderedDict
from pyparsing import originalTextFor, Literal, ZeroOrMore, Word, printables,\
OneOrMore, alphanums, ParseException, pyparsing_unicode,\
Group, Optional, alphas, lineEnd, lineStart, Keyword
class DovecotFormat(BaseFormat):
def __init__(self, document_text: str, ignore_comments=False):
processing_methods = [self._parse_comment_line,
self._parse_section_start_line,
self._parse_include_line,
self._parse_section_end_line,
self._parse_parameter_line,
self._parse_parameter_to_delete_line]
super().__init__(processing_methods)
self._ignore_comments = ignore_comments
self._need_finish = True
self._comments_processing = True
self._format = 'dovecot'
self._section_stack = OrderedDict()
self._current_section_name = ''
self._last_comments_list = []
self._initialize_parser()
if document_text == '':
self._document_dictionary = OrderedDict()
else:
document_lines = self._get_list_of_logic_lines(document_text)
self._lines_to_dictionary(document_lines)
def _initialize_parser(self):
# Знаки пунктуации и действий.
left_brace = Literal('{')
right_brace = Literal('}')
action_symbols = (Literal('!') | Literal('-'))
self._comment_line_parser = originalTextFor(
Literal('#')
+ ZeroOrMore(Word(
printables
+ pyparsing_unicode.alphanums)
)
)('comment')
# Для парсинга строк с началом секций.
section = Word(alphas, alphanums+'-_', excludeChars='{}')
section_name = Word(printables, excludeChars='{}')
self._section_start_parser = Group(Optional(action_symbols,
default='')('action')
+ section
+ Optional(section_name)
+ left_brace.suppress())('name')
# Для парсинга строк, указывающих конец секций.
self._section_end_parser = lineStart() + right_brace + lineEnd()
# Для парсинга строк, содержащих параметры.
parameter_name = Word(alphas, alphanums+'_-', excludeChars='{}=')
parameter_value = OneOrMore(Word(printables))
self._parameter_line_parser = (Group(Optional(action_symbols,
default='')('action')
+ parameter_name)('name')
+ Literal('=').suppress()
+ originalTextFor(
parameter_value
)('value'))
# Для парсинга строк с параметрами, подлежащими удалению.
self._parameter_to_delete_parser = (action_symbols('action')
+ parameter_name
+ Optional(Literal('=')).suppress()
)
# Для парсинга строк, содержащих директиву !include.
include = Keyword('!include') | Keyword('!include_try')
include_line_plain = (Optional(~action_symbols, default='')('action')
+ include('keyword') + Word(printables)('value'))
include_line_to_delete = (action_symbols('action') + include('keyword')
+ Word(printables)('value'))
self._include_line_parser = (include_line_plain |
include_line_to_delete)
def _parse_section_start_line(self, line):
try:
parsing_result = self._section_start_parser.parseString(line)
self._match = True
section_name = tuple(parsing_result.name.asList())
if not self._last_comments_list == []:
section_content = OrderedDict({'#': self._last_comments_list})
self._last_comments_list = []
else:
section_content = OrderedDict()
new_section = OrderedDict({section_name: section_content})
if self._section_stack == OrderedDict():
if section_name in self._document_dictionary:
new_section = OrderedDict(
{section_name:
self._document_dictionary[section_name]}
)
else:
if section_name in \
self._section_stack[self._current_section_name]:
new_section = OrderedDict({
section_name:
self._section_stack[self._current_section_name]
[section_name]
})
else:
self._section_stack[self._current_section_name].update(
new_section
)
self._section_stack.update(new_section)
self._current_section_name = section_name
except ParseException:
return
def _parse_section_end_line(self, line):
try:
self._section_end_parser.parseString(line)
self._match = True
last_section_name, last_section = self._section_stack.popitem()
if self._section_stack == OrderedDict():
self._item_to_add = OrderedDict({last_section_name:
last_section})
self._ready_to_update = True
self._current_section_name = ''
else:
self._current_section_name = next(reversed(
self._section_stack
))
except ParseException:
return
def _parse_parameter_line(self, line):
try:
parsing_result = self._parameter_line_parser.parseString(line)
self._match = True
parameter_name = tuple(parsing_result.name.asList())
parameter_value = (self._last_comments_list
+ [parsing_result.value.strip()])
self._last_comments_list = []
parameter = OrderedDict({parameter_name: parameter_value})
if self._section_stack == OrderedDict():
self._item_to_add = parameter
self._ready_to_update = True
else:
self._section_stack[self._current_section_name].update(
parameter
)
except ParseException:
return
def _parse_parameter_to_delete_line(self, line):
try:
parsing_result = self._parameter_to_delete_parser.parseString(line)
self._match = True
parameter_name = tuple(parsing_result.asList())
parameter_value = self._last_comments_list + ['']
self._last_comments_list = []
parameter = OrderedDict({parameter_name: parameter_value})
if self._section_stack == OrderedDict():
self._item_to_add = parameter
self._ready_to_update = True
else:
self._section_stack[self._current_section_name].update(
parameter
)
except ParseException:
return
def _parse_include_line(self, line):
try:
parsing_result = self._include_line_parser.parseString(line)
self._match = True
parameter_name = tuple(parsing_result.asList())
if parsing_result.action == '-':
return
parameter_value = self._last_comments_list + ['']
self._last_comments_list = []
include_item = OrderedDict({parameter_name: parameter_value})
if self._section_stack == OrderedDict():
self._item_to_add = include_item
self._ready_to_update = True
else:
self._section_stack[self._current_section_name].update(
include_item
)
except ParseException:
return
def _parse_comment_line(self, line):
try:
parsing_result = self._comment_line_parser.parseString(line)
self._match = True
if not self._ignore_comments:
self._last_comments_list.append(parsing_result.comment)
except ParseException:
return