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 'internal': "Crop, Lastfm, RandomFallBack",
52 'history_duration': "8",
64 'queue_mode': "track", #TODO control values
66 'single_album': "false",
74 'queue_mode': "track", #TODO control values
75 'single_album': "false",
81 'flavour': "sensible", # in pure, sensible, genre
88 class ConfMan(object): # CONFIG MANAGER CLASS
90 Configuration manager.
91 Default configuration is stored in DEFAULT_CONF dictionnary.
92 First init_config() run to get config from file.
93 Then control_conf() is run and retrieve configuration from defaults if not
95 These settings are then updated with command line options with
96 supersedes_config_with_cmd_line_options().
98 Order of priority for the origin of an option is then (lowest to highest):
100 * Env. Var for MPD host, port and password
101 * configuration file (overrides previous)
102 * command line options (overrides previous)
105 def __init__(self, logger, options=None):
106 # options settings priority:
107 # defauts < conf. file < command line
108 self.conf_file = options.get('conf_file')
110 self.defaults = dict(DEFAULT_CONF)
111 self.startopt = options
120 self.supersedes_config_with_cmd_line_options()
121 self.config['sima']['db_file'] = self.db_file
125 self.config.getboolean('MPD', 'password')
126 self.log.debug('No password set, proceeding without ' +
130 # ValueError if password not a boolean, hence an actual password.
131 pwd = self.config.get('MPD', 'password')
133 self.log.debug('Password set as an empty string.')
137 def control_mod(self):
139 Controls conf file permissions.
141 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
142 self.log.debug('file permission is: %o' % mode)
143 if mode & S_IRWXO or mode & S_IRWXG:
144 self.log.warning('File is readable by "other" and/or' +
145 ' "group" (actual permission %o octal).' %
147 self.log.warning('Consider setting permissions' +
150 def supersedes_config_with_cmd_line_options(self):
151 """Updates defaults settings with command line options"""
152 for sec in self.config.sections():
153 for opt in self.config.options(sec):
154 if opt in list(self.startopt.keys()):
155 self.config.set(sec, opt, str(self.startopt.get(opt)))
158 """Use MPD en.var. to set defaults"""
159 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
161 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
162 self.defaults['MPD']['host'] = mpd_host
164 self.log.info('Env. variable MPD_HOST contains password.')
165 self.defaults['MPD']['password'] = passwd
167 self.log.info('Env. variable MPD_PORT set to "%s".'
169 self.defaults['MPD']['port'] = mpd_port
171 def control_conf(self):
172 """Get through options/values and set defaults if not in conf file."""
173 # Control presence of obsolete settings
174 for option in ['history', 'history_length', 'top_tracks']:
175 if self.config.has_option('sima', option):
176 self.log.warning('Obsolete setting found in conf file: "%s"'
178 # Setting default if not specified
179 for section in DEFAULT_CONF.keys():
180 if section not in self.config.sections():
181 self.log.debug('[%s] NOT in conf file' % section)
182 self.config.add_section(section)
183 for option in self.defaults[section]:
184 self.config.set(section,
186 self.defaults[section][option])
188 'Setting option with default value: %s = %s' %
189 (option, self.defaults[section][option]))
190 elif section in self.config.sections():
191 self.log.debug('[%s] present in conf file' % section)
192 for option in self.defaults[section]:
193 if self.config.has_option(section, option):
194 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
195 # (option, self.config.get(section, option)))
199 'Option "%s" missing in section "%s"' %
201 self.log.debug('=> setting default "%s" (may not suit you…)' %
202 self.defaults[section][option])
203 self.config.set(section, option,
204 self.defaults[section][option])
206 def init_config(self):
208 Use XDG directory standard if exists
209 else use "HOME/(.config|.local/share)/sima/"
210 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
213 homedir = environ.get('HOME')
215 if environ.get('XDG_DATA_HOME'):
216 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
217 elif self.startopt.get('var_dir'):
218 # If var folder is provided via CLI set data_dir accordingly
219 data_dir = join(self.startopt.get('var_dir'))
220 elif (homedir and isdir(homedir) and homedir not in ['/']):
221 data_dir = join(homedir, '.local', 'share', DIRNAME)
223 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
224 self.log.error('Please use "--var_dir" to set a proper location')
227 if not isdir(data_dir):
229 chmod(data_dir, 0o700)
231 if self.startopt.get('conf_file'):
232 # No need to handle conf file location
234 elif environ.get('XDG_CONFIG_HOME'):
235 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
236 elif (homedir and isdir(homedir) and homedir not in ['/']):
237 conf_dir = join(homedir, '.config', DIRNAME)
238 # Create conf_dir if necessary
239 if not isdir(conf_dir):
241 chmod(conf_dir, 0o700)
242 self.conf_file = join(conf_dir, CONF_FILE)
244 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
245 self.log.error('Please use "--config" to locate the conf file')
248 self.db_file = join(data_dir, 'sima.db')
250 config = configparser.SafeConfigParser()
251 # If no conf file present, uses defaults
252 if not isfile(self.conf_file):
256 self.log.info('Loading configuration from: %s' % self.conf_file)
260 config.read(self.conf_file)
268 # vim: ai ts=4 sw=4 sts=4 expandtab