]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Python Config Generator: basic scaffolding
authorMaria Matejka <mq@ucw.cz>
Wed, 17 May 2023 11:20:28 +0000 (13:20 +0200)
committerMaria Matejka <mq@ucw.cz>
Tue, 23 May 2023 11:44:48 +0000 (13:44 +0200)
python/BIRD/Config.py [new file with mode: 0644]
python/BIRD/__init__.py
python/conftest.py [new file with mode: 0644]

diff --git a/python/BIRD/Config.py b/python/BIRD/Config.py
new file mode 100644 (file)
index 0000000..1c9d729
--- /dev/null
@@ -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"
+
index 26ce4d1eab365c42286cb1e15ba89399171e6aa7..bec04011c56b0331ec5ed005887fefa578a8197d 100644 (file)
@@ -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 (file)
index 0000000..50cfd46
--- /dev/null
@@ -0,0 +1,4 @@
+from BIRD import Config
+
+Config().write("test.conf")
+