Mercurial > libervia-backend
comparison libervia/backend/tools/config.py @ 4071:4b842c1fb686
refactoring: renamed `sat` package to `libervia.backend`
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 02 Jun 2023 11:49:51 +0200 |
parents | sat/tools/config.py@524856bd7b19 |
children | 0d7bb4df2343 |
comparison
equal
deleted
inserted
replaced
4070:d10748475025 | 4071:4b842c1fb686 |
---|---|
1 #!/usr/bin/env python3 | |
2 | |
3 | |
4 # SAT: a jabber client | |
5 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) | |
6 # Copyright (C) 2013-2016 Adrien Cossa (souliane@mailoo.org) | |
7 | |
8 # This program is free software: you can redistribute it and/or modify | |
9 # it under the terms of the GNU Affero General Public License as published by | |
10 # the Free Software Foundation, either version 3 of the License, or | |
11 # (at your option) any later version. | |
12 | |
13 # This program is distributed in the hope that it will be useful, | |
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 # GNU Affero General Public License for more details. | |
17 | |
18 # You should have received a copy of the GNU Affero General Public License | |
19 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 | |
21 """ Configuration related useful methods """ | |
22 | |
23 import os | |
24 import csv | |
25 import json | |
26 from typing import Any | |
27 from configparser import ConfigParser, DEFAULTSECT, NoOptionError, NoSectionError | |
28 from xdg import BaseDirectory | |
29 from libervia.backend.core.log import getLogger | |
30 from libervia.backend.core.constants import Const as C | |
31 from libervia.backend.core.i18n import _ | |
32 from libervia.backend.core import exceptions | |
33 | |
34 log = getLogger(__name__) | |
35 | |
36 | |
37 def fix_config_option(section, option, value, silent=True): | |
38 """Force a configuration option value | |
39 | |
40 the option will be written in the first found user config file, a new user | |
41 config will be created if none is found. | |
42 | |
43 @param section (str): the config section | |
44 @param option (str): the config option | |
45 @param value (str): the new value | |
46 @param silent (boolean): toggle logging output (must be True when called from sat.sh) | |
47 """ | |
48 config = ConfigParser() | |
49 target_file = None | |
50 for file_ in C.CONFIG_FILES[::-1]: | |
51 # we will eventually update the existing file with the highest priority, | |
52 # if it's a user personal file... | |
53 if not silent: | |
54 log.debug(_("Testing file %s") % file_) | |
55 if os.path.isfile(file_): | |
56 if file_.startswith(os.path.expanduser("~")): | |
57 config.read([file_]) | |
58 target_file = file_ | |
59 break | |
60 if not target_file: | |
61 # ... otherwise we create a new config file for that user | |
62 target_file = ( | |
63 f"{BaseDirectory.save_config_path(C.APP_NAME_FILE)}/{C.APP_NAME_FILE}.conf" | |
64 ) | |
65 if section and section.upper() != DEFAULTSECT and not config.has_section(section): | |
66 config.add_section(section) | |
67 config.set(section, option, value) | |
68 with open(target_file, "wb") as configfile: | |
69 config.write(configfile) # for the next time that user launches sat | |
70 if not silent: | |
71 if option in ("passphrase",): # list here the options storing a password | |
72 value = "******" | |
73 log.warning(_("Config auto-update: {option} set to {value} in the file " | |
74 "{config_file}.").format(option=option, value=value, | |
75 config_file=target_file)) | |
76 | |
77 | |
78 def parse_main_conf(log_filenames=False): | |
79 """Look for main .ini configuration file, and parse it | |
80 | |
81 @param log_filenames(bool): if True, log filenames of read config files | |
82 """ | |
83 config = ConfigParser(defaults=C.DEFAULT_CONFIG) | |
84 try: | |
85 filenames = config.read(C.CONFIG_FILES) | |
86 except Exception as e: | |
87 log.error(_("Can't read main config: {msg}").format(msg=e), exc_info=True) | |
88 else: | |
89 if log_filenames: | |
90 if filenames: | |
91 log.info( | |
92 _("Configuration was read from: {filenames}").format( | |
93 filenames=', '.join(filenames))) | |
94 else: | |
95 log.warning( | |
96 _("No configuration file found, using default settings") | |
97 ) | |
98 | |
99 return config | |
100 | |
101 | |
102 def config_get(config, section, name, default=None): | |
103 """Get a configuration option | |
104 | |
105 @param config (ConfigParser): the configuration instance | |
106 @param section (str): section of the config file (None or '' for DEFAULT) | |
107 @param name (str): name of the option | |
108 @param default: value to use if not found, or Exception to raise an exception | |
109 @return (unicode, list, dict): parsed value | |
110 @raise: NoOptionError if option is not present and default is Exception | |
111 NoSectionError if section doesn't exists and default is Exception | |
112 exceptions.ParsingError error while parsing value | |
113 """ | |
114 if not section: | |
115 section = DEFAULTSECT | |
116 | |
117 try: | |
118 value = config.get(section, name) | |
119 except (NoOptionError, NoSectionError) as e: | |
120 if default is Exception: | |
121 raise e | |
122 return default | |
123 | |
124 if name.endswith("_path") or name.endswith("_dir"): | |
125 value = os.path.expanduser(value) | |
126 # thx to Brian (http://stackoverflow.com/questions/186857/splitting-a-semicolon-separated-string-to-a-dictionary-in-python/186873#186873) | |
127 elif name.endswith("_list"): | |
128 value = next(csv.reader( | |
129 [value], delimiter=",", quotechar='"', skipinitialspace=True | |
130 )) | |
131 elif name.endswith("_dict"): | |
132 try: | |
133 value = json.loads(value) | |
134 except ValueError as e: | |
135 raise exceptions.ParsingError("Error while parsing data: {}".format(e)) | |
136 if not isinstance(value, dict): | |
137 raise exceptions.ParsingError( | |
138 "{name} value is not a dict: {value}".format(name=name, value=value) | |
139 ) | |
140 elif name.endswith("_json"): | |
141 try: | |
142 value = json.loads(value) | |
143 except ValueError as e: | |
144 raise exceptions.ParsingError("Error while parsing data: {}".format(e)) | |
145 return value | |
146 | |
147 | |
148 def get_conf( | |
149 conf: ConfigParser, | |
150 prefix: str, | |
151 section: str, | |
152 name: str, | |
153 default: Any | |
154 ) -> Any: | |
155 """Get configuration value from environment or config file | |
156 | |
157 @param str: prefix to use for the varilable name (see `name` below) | |
158 @param section: config section to use | |
159 @param name: unsuffixed name. | |
160 For environment variable, `LIBERVIA_<prefix>_` will be prefixed (and name | |
161 will be set to uppercase). | |
162 For config file, `<prefix>_` will be prefixed (and DEFAULT section will be | |
163 used). | |
164 Environment variable has priority over config values. If Environment variable | |
165 is set but empty string, config value will be used. | |
166 @param default: default value to use if varilable is set neither in environment, | |
167 nor in config | |
168 """ | |
169 # XXX: This is a temporary method until parameters are refactored | |
170 value = os.getenv(f"LIBERVIA_{prefix}_{name}".upper()) | |
171 return value or config_get(conf, section, f"{prefix}_{name}", default) |