mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +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 datetime import datetime
|
||||||
from weakref import WeakKeyDictionary
|
from weakref import WeakKeyDictionary
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
|
||||||
class ConfigObject:
|
class ConfigObject:
|
||||||
def __init__(self):
|
def __init__(self, comment=None):
|
||||||
self.symbols = {}
|
self.symbols = {}
|
||||||
self.config = WeakKeyDictionary()
|
self.config = WeakKeyDictionary()
|
||||||
self.comment = None
|
self.comment = comment
|
||||||
|
|
||||||
def __str__(self):
|
def isp(self, indent):
|
||||||
return "" if self.comment is None else f"# {self.comment}\n"
|
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):
|
class Timestamp(ConfigObject):
|
||||||
def __init__(self, comment):
|
def __init__(self, comment):
|
||||||
super().__init__()
|
super().__init__(comment=f"{comment} at {datetime.now()}")
|
||||||
self.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):
|
if not isinstance(value, _type):
|
||||||
raise Exception("BlockOption value doesn't match declared type")
|
raise Exception("BlockOption value doesn't match declared type")
|
||||||
|
|
||||||
@ -24,47 +36,59 @@ class BlockOption:
|
|||||||
self._type = _type
|
self._type = _type
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def set(self, value):
|
def set(self, value, **kwargs):
|
||||||
if value == self.value:
|
if value == self.value and len(kwargs) == 0:
|
||||||
return self
|
return self
|
||||||
else:
|
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 = {
|
options = {
|
||||||
"disabled": BlockOption("disabled", bool, False),
|
"disabled": BlockOption("disabled", bool, False),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, name=None, template=None, **kwargs):
|
def __init__(self, name=None, template=None, **kwargs):
|
||||||
super().__init__()
|
super().__init__(**kwargs)
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
if template is not None:
|
if template is not None:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
self.options_set = {}
|
def block_header(self):
|
||||||
for k in kwargs:
|
return f"protocol {self.protocol_type}{'' if self.name is None else ' ' + self.name }"
|
||||||
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"
|
|
||||||
|
|
||||||
class DeviceProtocolConfig(ProtocolConfig):
|
class DeviceProtocolConfig(ProtocolConfig):
|
||||||
name_prefix = "device"
|
name_prefix = "device"
|
||||||
|
@ -23,7 +23,7 @@ class Config:
|
|||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
if self.config.auto_device:
|
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.begin = Timestamp("Config dump started")
|
||||||
self.config.add(self.begin)
|
self.config.add(self.begin)
|
||||||
@ -37,12 +37,12 @@ class Config:
|
|||||||
if isinstance(i, DeviceProtocolConfig):
|
if isinstance(i, DeviceProtocolConfig):
|
||||||
self.auto_device = None
|
self.auto_device = None
|
||||||
|
|
||||||
_file.write(str(i))
|
i.writelines(_file)
|
||||||
|
|
||||||
if self.auto_device is not None:
|
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):
|
def __exit__(self, *args):
|
||||||
self.config.remove(self.begin)
|
self.config.remove(self.begin)
|
||||||
|
@ -2,6 +2,8 @@ from BIRD import Config
|
|||||||
from BIRD.Config import DeviceProtocolConfig
|
from BIRD.Config import DeviceProtocolConfig
|
||||||
|
|
||||||
cf = Config()
|
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")
|
cf.write("test.conf")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user