1 # -*- coding: utf-8 -*-
3 # Copyright (c) 2009, 2010, 2011, 2013 Jack Kaliko <kaliko@azylum.org>
5 # This file is part of sima
7 # sima is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # sima is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with sima. If not, see <http://www.gnu.org/licenses/>.
23 Deal with configuration and data files.
24 Parse configuration file and set defaults for missing options.
31 from configparser import Error
32 from os import (makedirs, environ, stat, chmod)
33 from os.path import (join, isdir, isfile)
34 from stat import (S_IMODE, ST_MODE, S_IRWXO, S_IRWXG)
40 CONF_FILE = 'sima.cfg'
49 'history_duration': "8",
60 'queue_mode': "track", #TODO control values
61 'single_album': "false",
67 'flavour': "sensible", # in pure, sensible, genre
74 class ConfMan(object): # CONFIG MANAGER CLASS
76 Configuration manager.
77 Default configuration is stored in DEFAULT_CONF dictionnary.
78 First init_config() run to get config from file.
79 Then control_conf() is run and retrieve configuration from defaults if not
81 These settings are then updated with command line options with
82 supersedes_config_with_cmd_line_options().
84 Order of priority for the origin of an option is then (lowest to highest):
86 * Env. Var for MPD host, port and password
87 * configuration file (overrides previous)
88 * command line options (overrides previous)
91 def __init__(self, logger, options=None):
92 # options settings priority:
93 # defauts < conf. file < command line
94 self.conf_file = options.get('conf_file')
96 self.defaults = dict(DEFAULT_CONF)
97 self.startopt = options
106 self.supersedes_config_with_cmd_line_options()
110 self.config.getboolean('MPD', 'password')
111 self.log.debug('No password set, proceeding without ' +
115 # ValueError if password not a boolean, hence an actual password.
116 pw = self.config.get('MPD', 'password')
118 self.log.debug('Password set as an empty string.')
122 def control_mod(self):
124 Controls conf file permissions.
126 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
127 self.log.debug('file permission is: %o' % mode)
128 if mode & S_IRWXO or mode & S_IRWXG:
129 self.log.warning('File is readable by "other" and/or' +
130 ' "group" (actual permission %o octal).' %
132 self.log.warning('Consider setting permissions' +
135 def supersedes_config_with_cmd_line_options(self):
136 """Updates defaults settings with command line options"""
137 for sec in self.config.sections():
138 for opt in self.config.options(sec):
139 if opt in list(self.startopt.keys()):
140 self.config.set(sec, opt, str(self.startopt.get(opt)))
143 """Use MPD en.var. to set defaults"""
144 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
146 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
147 self.defaults['MPD']['host'] = mpd_host
149 self.log.info('Env. variable MPD_HOST contains password.')
150 self.defaults['MPD']['password'] = passwd
152 self.log.info('Env. variable MPD_PORT set to "%s".'
154 self.defaults['MPD']['port'] = mpd_port
156 def control_conf(self):
157 """Get through options/values and set defaults if not in conf file."""
158 # Control presence of obsolete settings
159 for option in ['history', 'history_length', 'top_tracks']:
160 if self.config.has_option('sima', option):
161 self.log.warning('Obsolete setting found in conf file: "%s"'
163 # Setting default if not specified
164 for section in DEFAULT_CONF.keys():
165 if section not in self.config.sections():
166 self.log.debug('[%s] NOT in conf file' % section)
167 self.config.add_section(section)
168 for option in self.defaults[section]:
169 self.config.set(section,
171 self.defaults[section][option])
173 'Setting option with default value: %s = %s' %
174 (option, self.defaults[section][option]))
175 elif section in self.config.sections():
176 self.log.debug('[%s] present in conf file' % section)
177 for option in self.defaults[section]:
178 if self.config.has_option(section, option):
179 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
180 # (option, self.config.get(section, option)))
184 'Option "%s" missing in section "%s"' %
186 self.log.debug('=> setting default "%s" (may not suit you…)' %
187 self.defaults[section][option])
188 self.config.set(section, option,
189 self.defaults[section][option])
191 def init_config(self):
193 Use XDG directory standard if exists
194 else use "HOME/(.config|.local/share)/sima/"
195 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
198 homedir = environ.get('HOME')
200 if environ.get('XDG_DATA_HOME'):
201 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
202 elif self.startopt.get('var_dir'):
203 # If var folder is provided via CLI set data_dir accordingly
204 data_dir = join(self.startopt.get('var_dir'))
205 elif (homedir and isdir(homedir) and homedir not in ['/']):
206 data_dir = join(homedir, '.local', 'share', DIRNAME)
208 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
209 self.log.error('Please use "--var_dir" to set a proper location')
212 if not isdir(data_dir):
214 chmod(data_dir, 0o700)
216 if self.startopt.get('conf_file'):
217 # No need to handle conf file location
219 elif environ.get('XDG_CONFIG_HOME'):
220 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
221 elif (homedir and isdir(homedir) and homedir not in ['/']):
222 conf_dir = join(homedir, '.config', DIRNAME)
223 # Create conf_dir if necessary
224 if not isdir(conf_dir):
226 chmod(conf_dir, 0o700)
227 self.conf_file = join(conf_dir, CONF_FILE)
229 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
230 self.log.error('Please use "--config" to locate the conf file')
233 self.db_file = join(data_dir, 'sima.db')
235 config = configparser.SafeConfigParser()
237 # If no conf file present, uses defaults
238 if not isfile(self.conf_file):
242 self.log.info('Loading configuration from: %s' % self.conf_file)
246 config.read(self.conf_file)
254 # vim: ai ts=4 sw=4 sts=4 expandtab