mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Python Config Generator: allow comments everywhere
This commit is contained in:
parent
49ac4bd161
commit
8496c4b469
@ -1,22 +1,34 @@
|
||||
from datetime import datetime
|
||||
from weakref import WeakKeyDictionary
|
||||
|
||||
import itertools
|
||||
|
||||
class ConfigObject:
|
||||
def __init__(self):
|
||||
def __init__(self, comment=None):
|
||||
self.symbols = {}
|
||||
self.config = WeakKeyDictionary()
|
||||
self.comment = None
|
||||
self.comment = comment
|
||||
|
||||
def __str__(self):
|
||||
return "" if self.comment is None else f"# {self.comment}\n"
|
||||
def isp(self, indent):
|
||||
return " " * indent
|
||||
|
||||
def append(self):
|
||||
return "" if self.comment is None else f" # {self.comment}"
|
||||
|
||||
def lines(self, indent):
|
||||
return [] if self.comment is None else [ f"{self.isp(indent)}# {self.comment}" ]
|
||||
|
||||
def writelines(self, f):
|
||||
f.writelines([ x + "\n" for x in self.lines(0) ])
|
||||
|
||||
class Timestamp(ConfigObject):
|
||||
def __init__(self, comment):
|
||||
super().__init__()
|
||||
self.comment = f"{comment} at {datetime.now()}"
|
||||
super().__init__(comment=f"{comment} at {datetime.now()}")
|
||||
|
||||
class BlockOption(ConfigObject):
|
||||
def __init__(self, config_text, _type, value, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
class BlockOption:
|
||||
def __init__(self, config_text, _type, value):
|
||||
if not isinstance(value, _type):
|
||||
raise Exception("BlockOption value doesn't match declared type")
|
||||
|
||||
@ -24,47 +36,59 @@ class BlockOption:
|
||||
self._type = _type
|
||||
self.value = value
|
||||
|
||||
def set(self, value):
|
||||
if value == self.value:
|
||||
def set(self, value, **kwargs):
|
||||
if value == self.value and len(kwargs) == 0:
|
||||
return self
|
||||
else:
|
||||
return type(self)(self.config_text, self._type, value)
|
||||
return type(self)(self.config_text, self._type, value, **kwargs)
|
||||
|
||||
class ProtocolConfig(ConfigObject):
|
||||
def lines(self, indent):
|
||||
return [ f"{self.isp(indent)}{self.config_text} {self.value};{self.append()}" ]
|
||||
|
||||
class ConfigBlock(ConfigObject):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**{ k:v for k,v in kwargs.items() if k not in self.options })
|
||||
|
||||
self.options_set = {}
|
||||
for k,v in kwargs.items():
|
||||
if k in self.options:
|
||||
self.options_set[k] = self.options[k].set(v)
|
||||
|
||||
def set(self, arg, val, **kwargs):
|
||||
if arg not in self.options:
|
||||
raise NotImplementedError
|
||||
|
||||
self.options_set[arg] = self.options[arg].set(val, **kwargs)
|
||||
|
||||
def lines(self, indent):
|
||||
inside = [
|
||||
(opt.lines(indent+1))
|
||||
for k,opt in self.options_set.items()
|
||||
if opt != self.options[k]
|
||||
]
|
||||
|
||||
header = self.block_header()
|
||||
isp = " " * indent
|
||||
|
||||
if len(inside) == 0:
|
||||
return [ header + " {}" + self.append() ]
|
||||
else:
|
||||
return [ *super().lines(indent), isp + header + " {", *itertools.chain(*inside), isp + "}" ]
|
||||
|
||||
class ProtocolConfig(ConfigBlock):
|
||||
options = {
|
||||
"disabled": BlockOption("disabled", bool, False),
|
||||
}
|
||||
|
||||
def __init__(self, name=None, template=None, **kwargs):
|
||||
super().__init__()
|
||||
super().__init__(**kwargs)
|
||||
self.name = name
|
||||
|
||||
if template is not None:
|
||||
raise NotImplementedError()
|
||||
|
||||
self.options_set = {}
|
||||
for k in kwargs:
|
||||
if k not in self.options:
|
||||
raise NotImplementedError()
|
||||
|
||||
self.options_set[k] = self.options[k].set(kwargs[k])
|
||||
|
||||
def block_inside(self, indent):
|
||||
if len(self.options_set) == 0:
|
||||
return None
|
||||
|
||||
return ("\n" + " " * indent).join([""] + [
|
||||
f"{opt.config_text} {opt.value};" for k,opt in self.options_set.items() if opt != self.options[k]
|
||||
])
|
||||
|
||||
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 + " {" + inside + "\n}\n"
|
||||
def block_header(self):
|
||||
return f"protocol {self.protocol_type}{'' if self.name is None else ' ' + self.name }"
|
||||
|
||||
class DeviceProtocolConfig(ProtocolConfig):
|
||||
name_prefix = "device"
|
||||
|
@ -23,7 +23,7 @@ class Config:
|
||||
|
||||
def __enter__(self):
|
||||
if self.config.auto_device:
|
||||
self.auto_device = DeviceProtocolConfig()
|
||||
self.auto_device = DeviceProtocolConfig(comment="Default device protocol; set Config(auto_device=False) to remove")
|
||||
|
||||
self.begin = Timestamp("Config dump started")
|
||||
self.config.add(self.begin)
|
||||
@ -37,12 +37,12 @@ class Config:
|
||||
if isinstance(i, DeviceProtocolConfig):
|
||||
self.auto_device = None
|
||||
|
||||
_file.write(str(i))
|
||||
i.writelines(_file)
|
||||
|
||||
if self.auto_device is not None:
|
||||
_file.write(str(self.auto_device))
|
||||
self.auto_device.writelines(_file)
|
||||
|
||||
_file.write(str(Timestamp("Config dump finished")))
|
||||
Timestamp("Config dump finished").writelines(_file)
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.config.remove(self.begin)
|
||||
|
@ -2,6 +2,8 @@ from BIRD import Config
|
||||
from BIRD.Config import DeviceProtocolConfig
|
||||
|
||||
cf = Config()
|
||||
cf.add(DeviceProtocolConfig(name="foo", scan_time=42))
|
||||
cf.add(dev := DeviceProtocolConfig(name="foo", comment="my own device protocol"))
|
||||
dev.set("scan_time", 86400, comment="once a day, my interfaces never change")
|
||||
#cf.add(DeviceProtocolConfig(name="foo", scan_time=42, comment="my own device protocol"))
|
||||
cf.write("test.conf")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user