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.

129 lines
4.9 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
#
from .base_format import Format
from collections import OrderedDict
from pyparsing import Word, Literal, alphanums, printables, originalTextFor,\
OneOrMore, ParseException, restOfLine, Group, Optional,\
Regex
class ProcmailFormat(Format):
FORMAT = 'procmail'
EXECUTABLE = False
_initialized = False
comment_symbol = '#'
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str,
template_path,
ignore_comments=False,
join_before=False,
add_header=False,
already_changed=False,
**kwargs):
processing_methods = [self._parse_comment_line,
self._parse_parameter_line,
self._parse_to_delete_line]
super().__init__(processing_methods)
self._ignore_comments = ignore_comments
self._comments_processing = True
self._join_before = join_before
self._last_comments_list = []
if add_header and not ignore_comments:
self.header, document_text = self._get_header_and_document_text(
document_text,
template_path,
already_changed=already_changed)
else:
self.header = ''
document_text = document_text.strip()
if document_text == '':
self._document_dictionary = OrderedDict()
else:
document_lines = self._get_list_of_logic_lines(document_text)
self._lines_to_dictionary(document_lines)
@classmethod
def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
parameter_name = Word(alphanums+'_.')
parameter_value = originalTextFor(OneOrMore(Word(printables)))
action_symbols = (Literal('!') | Literal('-'))
cls._parameter_line = (Group(Optional(action_symbols,
default='')('action')
+ parameter_name('Name')
)('parameter_name')
+ Literal('=').suppress()
+ parameter_value('parameter_value'))
cls._parameter_to_delete = (Group(action_symbols('action')
+ parameter_name('Name')
)('parameter_name')
+ restOfLine.suppress())
cls._comment_line = originalTextFor(Literal(cls.comment_symbol)
+ Regex(r'.*'))('comment')
cls._initialized = True
def _parse_parameter_line(self, line):
'''Метод для парсинга строк содержащих параметр.'''
try:
parsing_result = self._parameter_line.parseString(line)
self._match = True
key_value = tuple(parsing_result.parameter_name.asList())
parameter_value = parsing_result.parameter_value
parameter_value = self._last_comments_list + [parameter_value]
self._last_comments_list = []
self._item_to_add = OrderedDict({key_value: parameter_value})
self._ready_to_update = True
except ParseException:
return
def _parse_to_delete_line(self, line):
'''Метод для парсинга строк, подлежащих удалению, т.е. для которых
указано имя параметра со знаком !, и опционально присутствует значение
параметра.'''
try:
self._item_to_add = OrderedDict()
parsing_result = self._parameter_to_delete.parseString(line)
self._match = True
if parsing_result.parameter_name.action == '-':
return
key_value = tuple(parsing_result.parameter_name.asList())
parameter_value = self._last_comments_list
self._last_comments_list = []
self._item_to_add = OrderedDict({key_value: parameter_value})
self._ready_to_update = True
except ParseException:
return
def _parse_comment_line(self, line):
'''Метод для парсинга строк содержащих комментарий.'''
try:
parsing_result = self._comment_line.parseString(line)
self._match = True
if not self._ignore_comments:
self._last_comments_list.append(parsing_result.comment)
except ParseException:
return