# vim: fileencoding=utf-8 # from .base_format import Format from calculate.utils.package import ( PackageAtomParser, PackageNotFound, PackageAtomError ) from collections import OrderedDict from typing import List import os class WorldFormat(Format): FORMAT = 'world' EXECUTABLE = False _initialized = False comment_symbol = '#' def __init__(self, document_text: str, template_path: str, ignore_comments: bool = False, add_header: bool = False, already_changed: bool = False, chroot_path="/", **kwargs): processing_methods = [] self._atom_parser = PackageAtomParser(chroot_path=chroot_path) super().__init__(processing_methods) self._template_name = os.path.basename(template_path) self._action_symbols = ["!!", "!"] self.warnings = [] 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._document_dictionary = self._lines_to_dictionary( document_lines) def _lines_to_dictionary(self, document_lines: List[str]) -> OrderedDict: output = OrderedDict() for line in document_lines: action = None for action_symbol in self._action_symbols: if line.startswith(action_symbol): action = action_symbol line = line[len(action_symbol):] break name_only = line.split(':')[0] if "/" not in name_only: line = f"{self._template_name}/{line}" atom_dict = self._atom_parser.parse_atom_name(line) atom_dict['package_atom'] = ( f'{atom_dict["category"]}/{atom_dict["name"]}') if action == "!!": action = "!" print("WITH EXISTANCE CHECK") try: self._atom_parser._check_package_existance(atom_dict) print("PACKAGE WAS FOUND") except (PackageNotFound, PackageAtomError): print("PACKAGE WAS NOT FOUND") self.warnings.append(f"package '{line}' not found") levels = [atom_dict["category"], atom_dict["name"]] level = output for next_level in levels: if next_level not in level: level[next_level] = OrderedDict() level = level[next_level] level[atom_dict["slot"]] = action return output def join_template(self, template): self._document_dictionary = self._change_categories( template._document_dictionary, self._document_dictionary) def _change_categories(self, template: OrderedDict, original: OrderedDict) -> OrderedDict: for category, names in template.items(): if category in original: original_names = original[category] else: original_names = OrderedDict() changed_names = self._change_names(names, original_names) if not changed_names: original.pop(category) else: original[category] = changed_names return original def _change_names(self, template_names: OrderedDict, original_names: OrderedDict) -> OrderedDict: for name, slots in template_names.items(): if name in original_names: original_slots = original_names[name] else: original_slots = OrderedDict() changed_slots = self._change_slots(slots, original_slots) if not changed_slots: original_names.pop(name) else: original_names[name] = changed_slots return original_names def _change_slots(self, template_slots: OrderedDict, original_slots: OrderedDict) -> OrderedDict: for slot, action in template_slots.items(): if slot == "*": if action == "!": original_slots.clear() continue else: if action == "!" and slot in original_slots: original_slots.pop(slot) continue if action is None and slot not in original_slots: original_slots[slot] = None continue return original_slots def _get_document_text(self) -> str: lines = [] categories = sorted(self._document_dictionary.keys()) for category in categories: names_dict = self._document_dictionary[category] names = sorted(names_dict.keys()) for name in names: slots = sorted(names_dict[name].keys()) for slot in slots: slot = '' if slot is None else f":{slot}" lines.append(f"{category}/{name}{slot}") lines.append('') return "\n".join(lines) @property def document_text(self) -> str: return "{}{}".format(self.header, self._get_document_text())