Coverage for birdplan/bird_config/sections/base.py: 95%

76 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-23 03:27 +0000

1# 

2# SPDX-License-Identifier: GPL-3.0-or-later 

3# 

4# Copyright (c) 2019-2024, AllWorldIT 

5# 

6# This program is free software: you can redistribute it and/or modify 

7# it under the terms of the GNU General Public License as published by 

8# the Free Software Foundation, either version 3 of the License, or 

9# (at your option) any later version. 

10# 

11# This program is distributed in the hope that it will be useful, 

12# but WITHOUT ANY WARRANTY; without even the implied warranty of 

13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

14# GNU General Public License for more details. 

15# 

16# You should have received a copy of the GNU General Public License 

17# along with this program. If not, see <http://www.gnu.org/licenses/>. 

18 

19"""BIRD configuration section base class.""" 

20 

21from typing import Dict, List, Union 

22 

23from ..globals import BirdConfigGlobals 

24 

25__all__ = ["SectionBaseConfig", "SectionBase"] 

26 

27 

28# Types 

29SectionConfigItem = Union[str, List[str], "SectionBase"] 

30SectionConfigItemList = List[SectionConfigItem] 

31SectionConfigItems = Dict[int, SectionConfigItemList] 

32 

33 

34class SectionBaseConfig: # pylint: disable=too-few-public-methods 

35 """Configuration contents of the section.""" 

36 

37 _birdconfig_globals: BirdConfigGlobals 

38 _items: SectionConfigItems 

39 

40 def __init__(self, birdconfig_globals: BirdConfigGlobals) -> None: 

41 """Initialize object.""" 

42 self._birdconfig_globals = birdconfig_globals 

43 self._items = {} 

44 

45 def add(self, item: SectionConfigItem, order: int = 10, deferred: bool = False, debug: bool = False) -> None: 

46 """ 

47 Add configuration to the output we're going to generate. 

48 

49 Parameters 

50 ---------- 

51 item : SectionConfigItem 

52 Configuration to add, either a string, list of strings or another section. 

53 

54 order : int 

55 Ordering of the item to add. Defaults to `10`. 

56 

57 deferred : bool 

58 If the config item is a SectionBase, then rendering can be deferred until after configuration. 

59 This is needed for instance for the constants section, which other protocols may add to. 

60 

61 debug : bool 

62 The configuration provided should only be output when we are in debug mode. 

63 

64 """ 

65 # Sanity checks 

66 if deferred and not isinstance(item, SectionBase): 

67 raise RuntimeError("Only SectionBase objects can be used as deferred configuration") 

68 

69 # If we have a debug line, exclude it if we're not in debugging mode 

70 if debug and not self.birdconfig_globals.debug: 

71 return 

72 

73 # Make sure this ordering position is initialized 

74 if order not in self.items: 

75 self.items[order] = [] 

76 items = self.items[order] 

77 

78 # If this is an instance of a list, extend our lines by this list 

79 if isinstance(item, list): 

80 items.extend(item) 

81 # If it is an entire section, configure it and add the lines 

82 elif isinstance(item, SectionBase): 

83 # Check if we're rendering now or later 

84 if not deferred: 

85 item.configure() 

86 self.add(item.conf.lines) 

87 else: 

88 items.append(item) 

89 # Else just add it 

90 else: 

91 items.append(item) 

92 

93 def append(self, item: SectionConfigItem, deferred: bool = False, debug: bool = False) -> None: 

94 """ 

95 Add configuration to the output we're going to generate. 

96 

97 This uses an order of `50`, which is higher than add() that defaults to `10`. 

98 

99 Parameters 

100 ---------- 

101 item : SectionConfigItem 

102 Configuration to add, either a string, list of strings or another section. 

103 deferred : bool 

104 If the config item is a SectionBase, then rendering can be deferred until after configuration. 

105 This is needed for instance for the constants section, which other protocols may add to. 

106 debug : bool 

107 The configuration provided should only be output when we are in debug mode. 

108 

109 """ 

110 self.add(item=item, order=50, deferred=deferred, debug=debug) 

111 

112 def title(self, title: str, order: int = 10) -> None: 

113 """ 

114 Add a title block. 

115 

116 Parameters 

117 ---------- 

118 title : str 

119 Add a title block 

120 order : int 

121 Ordering of the item to add. Defaults to `10`. 

122 

123 """ 

124 self.add("#", order=order) 

125 self.add(f"# {title}", order=order) 

126 self.add("#", order=order) 

127 self.add("", order=order) 

128 

129 def append_title(self, title: str) -> None: 

130 """ 

131 Add a title block. 

132 

133 This uses an order of `50`, which is higher than title() that defaults to `10`. 

134 

135 Parameters 

136 ---------- 

137 title : str 

138 Add a title block 

139 

140 """ 

141 self.title(title=title, order=50) 

142 

143 @property 

144 def items(self) -> SectionConfigItems: 

145 """Return our configuration items.""" 

146 return self._items 

147 

148 @property 

149 def lines(self) -> List[str]: 

150 """Return our configuration lines.""" 

151 lines: List[str] = [] 

152 # Loop with configuration items in order 

153 for _, items in sorted(self._items.items()): 

154 # Loop with each list 

155 for item in items: 

156 # If it is a SectionBase it means it was deferred, so configure and extend 

157 if isinstance(item, SectionBase): 

158 item.configure() 

159 lines.extend(item.conf.lines) 

160 # Or its just normal strings, add them all 

161 elif isinstance(item, str): 

162 lines.append(item) 

163 # Or something really weird happened 

164 else: 

165 raise RuntimeError("We should only have 'str' and 'SectionBase' items") 

166 # Finally return 

167 return lines 

168 

169 @property 

170 def birdconfig_globals(self) -> BirdConfigGlobals: 

171 """Return our BirdConfig globals.""" 

172 return self._birdconfig_globals 

173 

174 

175class SectionBase: 

176 """Base class for a BIRD configuration section.""" 

177 

178 # Section title 

179 _section: str 

180 

181 # Globals 

182 _birdconfig_globals: BirdConfigGlobals 

183 

184 # Configuration lines to output 

185 _config: SectionBaseConfig 

186 

187 # pylint: disable=unused-argument 

188 def __init__(self, birdconfig_globals: BirdConfigGlobals) -> None: 

189 """ 

190 Initialize the object. 

191 

192 Returns 

193 ------- 

194 Nothing. 

195 

196 """ 

197 

198 self._section = "" 

199 

200 self._birdconfig_globals = birdconfig_globals 

201 

202 self._config = SectionBaseConfig(birdconfig_globals=self.birdconfig_globals) 

203 

204 def configure(self) -> None: 

205 """ 

206 Configure this section. 

207 

208 Returns 

209 ------- 

210 Nothing. 

211 

212 """ 

213 if self.section: 

214 self.conf.title(self.section) 

215 

216 @property 

217 def section(self) -> str: 

218 """Return the section name.""" 

219 return self._section 

220 

221 @property 

222 def birdconfig_globals(self) -> BirdConfigGlobals: 

223 """Return our BirdConfig globals.""" 

224 return self._birdconfig_globals 

225 

226 @property 

227 def conf(self) -> SectionBaseConfig: 

228 """Return the configuration object.""" 

229 return self._config