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
65 'single_album': "false",
73 'queue_mode': "track", #TODO control values
74 'single_album': "false",
80 'flavour': "sensible", # in pure, sensible, genre
87 class ConfMan(object): # CONFIG MANAGER CLASS
89 Configuration manager.
90 Default configuration is stored in DEFAULT_CONF dictionnary.
91 First init_config() run to get config from file.
92 Then control_conf() is run and retrieve configuration from defaults if not
94 These settings are then updated with command line options with
95 supersedes_config_with_cmd_line_options().
97 Order of priority for the origin of an option is then (lowest to highest):
99 * Env. Var for MPD host, port and password
100 * configuration file (overrides previous)
101 * command line options (overrides previous)
104 def __init__(self, logger, options=None):
105 # options settings priority:
106 # defauts < conf. file < command line
107 self.conf_file = options.get('conf_file')
109 self.defaults = dict(DEFAULT_CONF)
110 self.startopt = options
119 self.supersedes_config_with_cmd_line_options()
120 self.config['sima']['db_file'] = self.db_file
124 self.config.getboolean('MPD', 'password')
125 self.log.debug('No password set, proceeding without ' +
129 # ValueError if password not a boolean, hence an actual password.
130 pwd = self.config.get('MPD', 'password')
132 self.log.debug('Password set as an empty string.')
136 def control_mod(self):
138 Controls conf file permissions.
140 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
141 self.log.debug('file permission is: %o' % mode)
142 if mode & S_IRWXO or mode & S_IRWXG:
143 self.log.warning('File is readable by "other" and/or' +
144 ' "group" (actual permission %o octal).' %
146 self.log.warning('Consider setting permissions' +
149 def supersedes_config_with_cmd_line_options(self):
150 """Updates defaults settings with command line options"""
151 for sec in self.config.sections():
152 for opt in self.config.options(sec):
153 if opt in list(self.startopt.keys()):
154 self.config.set(sec, opt, str(self.startopt.get(opt)))
157 """Use MPD en.var. to set defaults"""
158 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
160 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
161 self.defaults['MPD']['host'] = mpd_host
163 self.log.info('Env. variable MPD_HOST contains password.')
164 self.defaults['MPD']['password'] = passwd
166 self.log.info('Env. variable MPD_PORT set to "%s".'
168 self.defaults['MPD']['port'] = mpd_port
170 def control_conf(self):
171 """Get through options/values and set defaults if not in conf file."""
172 # Control presence of obsolete settings
173 for option in ['history', 'history_length', 'top_tracks']:
174 if self.config.has_option('sima', option):
175 self.log.warning('Obsolete setting found in conf file: "%s"'
177 # Setting default if not specified
178 for section in DEFAULT_CONF.keys():
179 if section not in self.config.sections():
180 self.log.debug('[%s] NOT in conf file' % section)
181 self.config.add_section(section)
182 for option in self.defaults[section]:
183 self.config.set(section,
185 self.defaults[section][option])
187 'Setting option with default value: %s = %s' %
188 (option, self.defaults[section][option]))
189 elif section in self.config.sections():
190 self.log.debug('[%s] present in conf file' % section)
191 for option in self.defaults[section]:
192 if self.config.has_option(section, option):
193 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
194 # (option, self.config.get(section, option)))
198 'Option "%s" missing in section "%s"' %
200 self.log.debug('=> setting default "%s" (may not suit you…)' %
201 self.defaults[section][option])
202 self.config.set(section, option,
203 self.defaults[section][option])
205 def init_config(self):
207 Use XDG directory standard if exists
208 else use "HOME/(.config|.local/share)/sima/"
209 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
212 homedir = environ.get('HOME')
214 if environ.get('XDG_DATA_HOME'):
215 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
216 elif self.startopt.get('var_dir'):
217 # If var folder is provided via CLI set data_dir accordingly
218 data_dir = join(self.startopt.get('var_dir'))
219 elif (homedir and isdir(homedir) and homedir not in ['/']):
220 data_dir = join(homedir, '.local', 'share', DIRNAME)
222 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
223 self.log.error('Please use "--var_dir" to set a proper location')
226 if not isdir(data_dir):
228 chmod(data_dir, 0o700)
230 if self.startopt.get('conf_file'):
231 # No need to handle conf file location
233 elif environ.get('XDG_CONFIG_HOME'):
234 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
235 elif (homedir and isdir(homedir) and homedir not in ['/']):
236 conf_dir = join(homedir, '.config', DIRNAME)
237 # Create conf_dir if necessary
238 if not isdir(conf_dir):
240 chmod(conf_dir, 0o700)
241 self.conf_file = join(conf_dir, CONF_FILE)
243 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
244 self.log.error('Please use "--config" to locate the conf file')
247 self.db_file = join(data_dir, 'sima.db')
249 config = configparser.SafeConfigParser()
250 # If no conf file present, uses defaults
251 if not isfile(self.conf_file):
255 self.log.info('Loading configuration from: %s' % self.conf_file)
259 config.read(self.conf_file)
267 # vim: ai ts=4 sw=4 sts=4 expandtab