1 |
commit: 346f15b80151811fb0813d5f14195ae8d73b4d61 |
2 |
Author: André Erdmann <dywi <AT> mailerd <DOT> de> |
3 |
AuthorDate: Mon Jun 4 15:42:50 2012 +0000 |
4 |
Commit: André Erdmann <dywi <AT> mailerd <DOT> de> |
5 |
CommitDate: Mon Jun 4 15:42:50 2012 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=346f15b8 |
7 |
|
8 |
roverlay, config: fix typo and add main config reader |
9 |
|
10 |
modified: config.py |
11 |
|
12 |
--- |
13 |
roverlay/config.py | 172 ++++++++++++++++++++++++++++++++++++++++++++++++---- |
14 |
1 files changed, 159 insertions(+), 13 deletions(-) |
15 |
|
16 |
diff --git a/roverlay/config.py b/roverlay/config.py |
17 |
index 41a98bf..bce721c 100644 |
18 |
--- a/roverlay/config.py |
19 |
+++ b/roverlay/config.py |
20 |
@@ -2,9 +2,11 @@ |
21 |
# Copyright 2006-2012 Gentoo Foundation |
22 |
# Distributed under the terms of the GNU General Public License v2 |
23 |
|
24 |
+import copy |
25 |
+import os |
26 |
+import re |
27 |
import sys |
28 |
import shlex |
29 |
-import copy |
30 |
|
31 |
try: |
32 |
import configparser |
33 |
@@ -13,8 +15,6 @@ except ImportError as running_python2: |
34 |
import ConfigParser as configparser |
35 |
|
36 |
|
37 |
- |
38 |
- |
39 |
from roverlay import descriptionfields |
40 |
from roverlay import const |
41 |
|
42 |
@@ -51,8 +51,8 @@ class InitialLogger: |
43 |
known from the logging module and its output goes directly to sys.stderr. |
44 |
This can be used until the real logging has been configured. |
45 |
""" |
46 |
- self.debug = lambda x : sys.stderr.write ( "DBG " + str ( x ) + "\n" ) |
47 |
- self.info = lambda x : sys.stderr.write ( "INFO " + str ( x ) + "\n" ) |
48 |
+ self.debug = lambda x : sys.stdout.write ( "DBG " + str ( x ) + "\n" ) |
49 |
+ self.info = lambda x : sys.stdout.write ( "INFO " + str ( x ) + "\n" ) |
50 |
self.warning = lambda x : sys.stderr.write ( "WARN " + str ( x ) + "\n" ) |
51 |
self.error = lambda x : sys.stderr.write ( "ERR " + str ( x ) + "\n" ) |
52 |
self.critical = lambda x : sys.stderr.write ( "CRIT " + str ( x ) + "\n" ) |
53 |
@@ -64,6 +64,25 @@ class ConfigTree: |
54 |
# static access to the first created ConfigTree |
55 |
instance = None |
56 |
|
57 |
+ # the list of 'normal' config entries (no special config path) (in lowercase) |
58 |
+ # the map of config entries |
59 |
+ CONFIG_ENTRY_MAP = dict ( |
60 |
+ log_level = '', |
61 |
+ log_console = dict ( |
62 |
+ value_type = 'yesno', |
63 |
+ ), |
64 |
+ log_file = dict ( |
65 |
+ value_type = 'fs_file', |
66 |
+ ), |
67 |
+ ebuild_header = dict ( |
68 |
+ value_type = 'fs_file', |
69 |
+ ) |
70 |
+ |
71 |
+ ) |
72 |
+ |
73 |
+ DEFAULT_LIST_REGEX = re.compile ( '\s*[,;]{1}\s*' ) |
74 |
+ WHITESPACE = re.compile ( '\s+' ) |
75 |
+ |
76 |
def __init__ ( self, import_const=True ): |
77 |
"""Initializes an ConfigTree, which is a container for options/config values. |
78 |
values can be stored directly (such as the field_definitions) or in a |
79 |
@@ -89,19 +108,18 @@ class ConfigTree: |
80 |
# --- end of __init__ (...) --- |
81 |
|
82 |
|
83 |
- def _findpath ( self, path, root=None, create=False ): |
84 |
+ def _findpath ( self, path, root=None, create=False, value=None ): |
85 |
if path is None: |
86 |
return root |
87 |
elif isinstance ( path, str ): |
88 |
- path = path.split ( '.' ) if key else [] |
89 |
+ path = path.split ( '.' ) if path else [] |
90 |
|
91 |
config_position = self._config if root is None else root |
92 |
|
93 |
for k in path: |
94 |
if not k in config_position: |
95 |
if create: |
96 |
- config_position [k] = dict () |
97 |
- |
98 |
+ config_position [k] = value if k == path [-1] and value else dict () |
99 |
else: |
100 |
return None |
101 |
|
102 |
@@ -134,22 +152,130 @@ class ConfigTree: |
103 |
|
104 |
# --- end of get (...) --- |
105 |
|
106 |
+ def _add_entry ( self, option, value=None, config_root=None ): |
107 |
+ |
108 |
+ def make_and_verify_value ( value_type, value, entryconfig_ref ): |
109 |
+ |
110 |
+ def to_int ( val, fallback_value=-1 ): |
111 |
+ try: |
112 |
+ ret = int ( val ) |
113 |
+ return ret |
114 |
+ except ValueError as verr: |
115 |
+ return fallback_value |
116 |
+ # --- end of to_int (...) --- |
117 |
+ |
118 |
+ def yesno ( val ): |
119 |
+ if not val is None: |
120 |
+ to_check = str ( val ) . lower () |
121 |
+ if to_check in [ 'y', 'yes', '1', 'true', 'enabled', 'on' ]: |
122 |
+ return 1 |
123 |
+ elif to_check in [ 'n', 'no', '0', 'false', 'disabled', 'off' ]: |
124 |
+ return 0 |
125 |
+ |
126 |
+ self.logger.warning ( to_check + " is not a valid yesno value." ) |
127 |
+ return -1 |
128 |
+ # --- end of yesno (...) --- |
129 |
+ |
130 |
+ value = ConfigTree.WHITESPACE.sub ( ' ', value ) |
131 |
+ |
132 |
+ if not value_type: |
133 |
+ return value |
134 |
+ elif isinstance ( value_type, list ): |
135 |
+ vtypes = value_type |
136 |
+ elif isinstance ( value_type, str ): |
137 |
+ vtypes = value_type.split ( ':' ) |
138 |
+ else: |
139 |
+ self.logger.error ( "Unknown data type for value type." ) |
140 |
+ return value |
141 |
+ |
142 |
+ retval = value |
143 |
+ is_list = False |
144 |
+ for vtype in vtypes: |
145 |
+ if vtype == 'list': |
146 |
+ retval = ConfigTree.DEFAULT_LIST_REGEX.split ( retval ) |
147 |
+ is_list = True |
148 |
+ elif vtype == 'slist': |
149 |
+ retval = ConfigTree.WHITESPACE.split ( retval ) |
150 |
+ is_list = True |
151 |
+ elif vtype == 'yesno': |
152 |
+ retval = [ yesno ( x ) for x in retval ] if is_list else yesno ( retval ) |
153 |
+ elif vtype == 'int': |
154 |
+ retval = [ to_int ( x ) for x in retval ] if is_list else to_int ( retval ) |
155 |
+ |
156 |
+ else: |
157 |
+ self.logger.warning ( "unknown value type '" + vtype + "'." ) |
158 |
+ |
159 |
+ return retval |
160 |
+ # --- end of make_and_verify_value (...) --- |
161 |
+ |
162 |
+ |
163 |
+ real_option = option |
164 |
+ low_option = option.lower() |
165 |
+ if option and low_option in ConfigTree.CONFIG_ENTRY_MAP: |
166 |
+ cref = ConfigTree.CONFIG_ENTRY_MAP [low_option] |
167 |
+ |
168 |
+ if isinstance ( cref, str ) and cref in ConfigTree.CONFIG_ENTRY_MAP: |
169 |
+ option = low_option = cref |
170 |
+ cref = ConfigTree.CONFIG_ENTRY_MAP [cref] |
171 |
+ |
172 |
+ if cref is None: |
173 |
+ # deftly ignored |
174 |
+ return True |
175 |
+ |
176 |
+ |
177 |
+ |
178 |
+ path = None |
179 |
+ if 'path' in cref: |
180 |
+ path = cref ['path'] |
181 |
+ else: |
182 |
+ path = low_option.split ( '_' ) |
183 |
+ for n in range ( len ( path ) - 1 ): |
184 |
+ path [n] = path [n].upper() |
185 |
+ |
186 |
+ |
187 |
+ if path: |
188 |
+ |
189 |
+ if 'value_type' in cref: |
190 |
+ value = make_and_verify_value ( cref ['value_type'], value, cref ) |
191 |
+ |
192 |
+ if value: |
193 |
+ |
194 |
+ self.logger.debug ( |
195 |
+ "New config entry " + str ( option ) + |
196 |
+ " with path " + str ( path ) + |
197 |
+ " and value " + str ( value ) + "." |
198 |
+ ) |
199 |
+ |
200 |
+ self._findpath ( path, config_root, True, value ) |
201 |
+ |
202 |
+ return True |
203 |
+ else: |
204 |
+ self.logger.error ( |
205 |
+ "Option '" + str ( real_option ) + |
206 |
+ "' has an unusable value '" + str ( value ) + "'." |
207 |
+ ) |
208 |
+ # --- |
209 |
+ # --- |
210 |
+ |
211 |
+ self.logger.warning ( "Option '" + str ( real_option ) + "' is unknown." ) |
212 |
+ return False |
213 |
+ |
214 |
+ # --- end of _add_entry (...) --- |
215 |
+ |
216 |
def load_config ( self, config_file, start_section='' ): |
217 |
"""Loads a config file and integrates its content into the config tree. |
218 |
Older config entries may be overwritten. |
219 |
|
220 |
arguments: |
221 |
config_file -- path to the file that should be read |
222 |
- start_section -- relative root in the config tree as str or ref |
223 |
+ start_section -- relative root in the config tree as str |
224 |
""" |
225 |
|
226 |
config_root = None |
227 |
if start_section: |
228 |
if isinstance ( start_section, str ): |
229 |
config_root = self._findpath ( start_section, None, True ) |
230 |
- elif isinstance ( start_section, dict ): |
231 |
- config_root = start_section |
232 |
- else |
233 |
+ else: |
234 |
raise Exception ("bad usage") |
235 |
|
236 |
# load file |
237 |
@@ -157,6 +283,26 @@ class ConfigTree: |
238 |
try: |
239 |
fh = open ( config_file, 'r' ) |
240 |
reader = shlex.shlex ( fh ) |
241 |
+ reader.whitespace_split = False |
242 |
+ reader.wordchars += ' ./$()[]:+-@*~' |
243 |
+ |
244 |
+ nextline = lambda : ( reader.get_token() for n in range (3) ) |
245 |
+ |
246 |
+ option, equal, value = nextline () |
247 |
+ |
248 |
+ while equal == '=' or not ( option == value == reader.eof ): |
249 |
+ if equal == '=': |
250 |
+ self._add_entry ( option, value, config_root ) |
251 |
+ else: |
252 |
+ self.logger.warning ( |
253 |
+ "In '" + config_file + "', cannot parse this line: '" + |
254 |
+ str ( option ) + str ( equal ) + str ( value ) + "'." |
255 |
+ ) |
256 |
+ |
257 |
+ option, equal, value = nextline () |
258 |
+ |
259 |
+ |
260 |
+ |
261 |
if fh: |
262 |
fh.close () |