From 11bd97b69bce72211d6cdacbe17fbd33af23907d Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 17 May 2023 13:20:28 +0200 Subject: [PATCH] Python Config Generator: basic scaffolding --- python/BIRD/Config.py | 40 ++++++++++++++++++++++ python/BIRD/__init__.py | 76 +++++++++++++++++++++++++++++++++++++++++ python/conftest.py | 4 +++ 3 files changed, 120 insertions(+) create mode 100644 python/BIRD/Config.py create mode 100644 python/conftest.py diff --git a/python/BIRD/Config.py b/python/BIRD/Config.py new file mode 100644 index 00000000..1c9d7298 --- /dev/null +++ b/python/BIRD/Config.py @@ -0,0 +1,40 @@ +from datetime import datetime +from weakref import WeakKeyDictionary + +class ConfigObject: + def __init__(self): + self.symbols = {} + self.config = WeakKeyDictionary() + self.comment = None + + def __str__(self): + return "" if self.comment is None else f"# {self.comment}\n" + +class Timestamp(ConfigObject): + def __init__(self, comment): + super().__init__() + self.comment = f"{comment} at {datetime.now()}" + +class ProtocolConfig(ConfigObject): + def __init__(self, name=None, template=None): + super().__init__() + self.name = name + if template is not None: + raise NotImplementedError() + + def block_inside(self, indent): + return None + + def __str__(self): + inside = self.block_inside(1) + header = f"protocol {self.protocol_type}{'' if self.name is None else ' ' + self.name }" + + if inside is None: + return header + " {}\n" + else: + return header + " {\n" + inside + "}\n" + +class DeviceProtocolConfig(ProtocolConfig): + name_prefix = "device" + protocol_type = "device" + diff --git a/python/BIRD/__init__.py b/python/BIRD/__init__.py index 26ce4d1e..bec04011 100644 --- a/python/BIRD/__init__.py +++ b/python/BIRD/__init__.py @@ -1,10 +1,86 @@ import asyncio from pathlib import Path +from datetime import datetime from BIRD.Basic import BIRDException from BIRD.Socket import Socket from BIRD.Status import Status, Version +from BIRD.Config import Timestamp, ProtocolConfig, DeviceProtocolConfig + +class Config: + def __init__(self, auto_device=True): + self._items = [] + self.symbols = {} + self.auto_device = auto_device + + self.add(Timestamp("Config object created")) + + class FinalizedConfig: + def __init__(self, config): + self.config = config + self.auto_device = None + + def __enter__(self): + if self.config.auto_device: + self.auto_device = DeviceProtocolConfig() + self.config.add(self.auto_device) + + self.begin = Timestamp("Config dump started") + self.config.add(self.begin) + + return self + + def dump(self, _file): + for i in self.config._items: + if i is not None: + _file.write(str(i)) + + _file.write(str(Timestamp("Config dump finished"))) + + def __exit__(self, *args): + self.config.remove(self.begin) + if self.auto_device is not None: + self.config.remove(self.auto_device) + + def finalized(self): + return self.FinalizedConfig(self) + + def write(self, _file): + with self.finalized() as sf: + with open(_file, "w") as f: + sf.dump(f) + + def add(self, item): + # Merge defined symbols + for s in item.symbols: + if s in self.symbols: + # Found: rollback and fail + for s in item.symbols: + if s in self.symbols: + del self.symbols[s] + raise BIRDException("Can't add item to config: symbol {s} already exists") + self.symbols[s] = item.symbols[s] + + # Store backref (weak) + item.config[self] = len(self._items) + + # Fwdref + self._items.append(item) + + def remove(self, item): + # Check backref existence + if self not in item.config: + raise BIRDException("Can't remove item from config: isn't there") + + # Remove fwdref and cleanup Nones + self._items[item.config[self]] = None + while self._items[-1] is None: + self._items.pop() + + # Remove backref + del item.config[self] + class CLI: def __init__(self, name): self.socket = Socket(name) diff --git a/python/conftest.py b/python/conftest.py new file mode 100644 index 00000000..50cfd46c --- /dev/null +++ b/python/conftest.py @@ -0,0 +1,4 @@ +from BIRD import Config + +Config().write("test.conf") +