# vim: fileencoding=utf-8 # from .base_format import BaseFormat from collections import OrderedDict from jinja2 import PackageLoader, Environment from pyparsing import Literal, Regex, Word, nums, alphanums, Optional,\ ParseException class ContentsFormat(BaseFormat): FORMAT = 'contents' EXECUTABLE = False _initialized = False def __new__(cls, *args, **kwargs): '''Метод для инициализации парсеров.''' if not cls._initialized: cls._initialize_parser() return super().__new__(cls) def __init__(self, document_text: str, ignore_comments=False, join_before=False, parameters=None, template_parser=True): processing_methods = [self._parse_dir_line, self._parse_sym_line, self._parse_obj_line] super().__init__(processing_methods) self._ignore_comments = ignore_comments self._join_before = join_before # флаг для указания режима, в котором работает формат. # Если True => формат работает для наложения шаблонов; # Если False => формат работает для получения словаря, используемого # модулем package. self._template_parser_flag = template_parser if not self._initialized: 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) @classmethod def _initialize_parser(cls): action_symbols = (Literal('!') | Literal('-')) sym_keyword = Literal('sym') dir_keyword = Literal('dir') obj_keyword = Literal('obj') symlink_arrow = Literal('->') file_path = Regex(r'\S+') time_value = Word(nums) md5 = Word(alphanums) cls.sym_line = (Optional(action_symbols, default='')('action') + sym_keyword('type') + file_path('name') + symlink_arrow.suppress() + file_path('target') + time_value('time')) cls.dir_line = (Optional(action_symbols, default='')('action') + dir_keyword('type') + file_path('name')) cls.obj_line = (Optional(action_symbols, default='')('action') + obj_keyword('type') + file_path('name') + md5('md5') + time_value('time')) cls._initialized = True def _parse_sym_line(self, line): '''Метод для разбора строк типа sym.''' try: parsing_result = self.sym_line.parseString(line) self._match = True if self._template_parser_flag: output_name = (parsing_result.action, parsing_result.name) output_value = (parsing_result.type, parsing_result.target, parsing_result.time) self._item_to_add = OrderedDict({output_name: [output_value]}) else: output_name = parsing_result.name output_value = OrderedDict({'type': parsing_result.type, 'target': parsing_result.target, 'mtime': parsing_result.time}) self._item_to_add = OrderedDict({output_name: output_value}) self._ready_to_update = True except ParseException: return def _parse_dir_line(self, line): '''Метод для разбора строк типа dir.''' try: parsing_result = self.dir_line.parseString(line) self._match = True if self._template_parser_flag: output_name = (parsing_result.action, parsing_result.name) output_value = (parsing_result.type,) self._item_to_add = OrderedDict({output_name: [output_value]}) else: output_name = parsing_result.name output_value = OrderedDict({'type': parsing_result.type}) self._item_to_add = OrderedDict({output_name: output_value}) self._ready_to_update = True except ParseException: return def _parse_obj_line(self, line): '''Метод для разбора строк типа obj.''' try: parsing_result = self.obj_line.parseString(line) self._match = True if self._template_parser_flag: output_name = (parsing_result.action, parsing_result.name) output_value = (parsing_result.type, parsing_result.md5, parsing_result.time) self._item_to_add = OrderedDict({output_name: [output_value]}) else: output_name = parsing_result.name output_value = OrderedDict({'type': parsing_result.type, 'md5': parsing_result.md5, 'mtime': parsing_result.time}) self._item_to_add = OrderedDict({output_name: output_value}) self._ready_to_update = True except ParseException: return @property def document_text(self): '''Метод для получения текста результирующего документа. Представляет собой переопределение соответствующего метода базового класса, посколько в данном случае нужно учитывать режим работы формата. ''' file_loader = PackageLoader('calculate.templates.format', self.TEMPLATES_DIRECTORY) formats_environment = Environment(loader=file_loader, trim_blocks=True, lstrip_blocks=True) formats_environment.globals.update(zip=zip) formats_environment.add_extension('jinja2.ext.do') template = formats_environment.get_template(self.FORMAT) document_text = template.render( document_dictionary=self._document_dictionary, template_parser=self._template_parser_flag ) return document_text