1 # -*- coding: utf-8 -*-
2 # Copyright (c) 2009, 2010, 2011, 2013, 2014 Jack Kaliko <kaliko@azylum.org>
4 # This file is part of sima
6 # sima is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # sima is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with sima. If not, see <http://www.gnu.org/licenses/>.
22 Deal with configuration and data files.
23 Parse configuration file and set defaults for missing options.
30 from configparser import Error
31 from os import (makedirs, environ, stat, chmod)
32 from os.path import (join, isdir, isfile)
33 from stat import (S_IMODE, ST_MODE, S_IRWXO, S_IRWXG)
39 CONF_FILE = 'sima.cfg'
48 'internal': "Crop, Lastfm, RandomFallBack",
51 'history_duration': "8",
63 'queue_mode': "track", #TODO control values
65 'single_album': "false",
71 'queue_mode': "track", #TODO control values
73 'single_album': "false",
79 'flavour': "sensible", # in pure, sensible
86 class ConfMan(object): # CONFIG MANAGER CLASS
88 Configuration manager.
89 Default configuration is stored in DEFAULT_CONF dictionnary.
90 First init_config() run to get config from file.
91 Then control_conf() is run and retrieve configuration from defaults if not
93 These settings are then updated with command line options with
94 supersedes_config_with_cmd_line_options().
96 Order of priority for the origin of an option is then (lowest to highest):
98 * Env. Var for MPD host, port and password
99 * configuration file (overrides previous)
100 * command line options (overrides previous)
103 def __init__(self, logger, options=None):
104 # options settings priority:
105 # defauts < conf. file < command line
106 self.conf_file = options.get('conf_file')
108 self.defaults = dict(DEFAULT_CONF)
109 self.startopt = options
118 self.supersedes_config_with_cmd_line_options()
119 self.config['sima']['db_file'] = self.db_file
123 self.config.getboolean('MPD', 'password')
124 self.log.debug('No password set, proceeding without ' +
128 # ValueError if password not a boolean, hence an actual password.
129 pwd = self.config.get('MPD', 'password')
131 self.log.debug('Password set as an empty string.')
135 def control_mod(self):
137 Controls conf file permissions.
139 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
140 self.log.debug('file permission is: %o' % mode)
141 if mode & S_IRWXO or mode & S_IRWXG:
142 self.log.warning('File is readable by "other" and/or' +
143 ' "group" (actual permission %o octal).' %
145 self.log.warning('Consider setting permissions' +
148 def supersedes_config_with_cmd_line_options(self):
149 """Updates defaults settings with command line options"""
150 for sec in self.config.sections():
151 for opt in self.config.options(sec):
152 if opt in list(self.startopt.keys()):
153 self.config.set(sec, opt, str(self.startopt.get(opt)))
156 """Use MPD en.var. to set defaults"""
157 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
159 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
160 self.defaults['MPD']['host'] = mpd_host
162 self.log.info('Env. variable MPD_HOST contains password.')
163 self.defaults['MPD']['password'] = passwd
165 self.log.info('Env. variable MPD_PORT set to "%s".'
167 self.defaults['MPD']['port'] = mpd_port
169 def control_conf(self):
170 """Get through options/values and set defaults if not in conf file."""
171 # Control presence of obsolete settings
172 for option in ['history', 'history_length', 'top_tracks']:
173 if self.config.has_option('sima', option):
174 self.log.warning('Obsolete setting found in conf file: "%s"'
176 # Setting default if not specified
177 for section in DEFAULT_CONF.keys():
178 if section not in self.config.sections():
179 self.log.debug('[%s] NOT in conf file' % section)
180 self.config.add_section(section)
181 for option in self.defaults[section]:
182 self.config.set(section,
184 self.defaults[section][option])
186 'Setting option with default value: %s = %s' %
187 (option, self.defaults[section][option]))
188 elif section in self.config.sections():
189 self.log.debug('[%s] present in conf file' % section)
190 for option in self.defaults[section]:
191 if self.config.has_option(section, option):
192 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
193 # (option, self.config.get(section, option)))
197 'Option "%s" missing in section "%s"' %
199 self.log.debug('=> setting default "%s" (may not suit you…)' %
200 self.defaults[section][option])
201 self.config.set(section, option,
202 self.defaults[section][option])
204 def init_config(self):
206 Use XDG directory standard if exists
207 else use "HOME/(.config|.local/share)/sima/"
208 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
211 homedir = environ.get('HOME')
213 if environ.get('XDG_DATA_HOME'):
214 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
215 elif self.startopt.get('var_dir'):
216 # If var folder is provided via CLI set data_dir accordingly
217 data_dir = join(self.startopt.get('var_dir'))
218 elif (homedir and isdir(homedir) and homedir not in ['/']):
219 data_dir = join(homedir, '.local', 'share', DIRNAME)
221 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
222 self.log.error('Please use "--var_dir" to set a proper location')
225 if not isdir(data_dir):
227 chmod(data_dir, 0o700)
229 if self.startopt.get('conf_file'):
230 # No need to handle conf file location
232 elif environ.get('XDG_CONFIG_HOME'):
233 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
234 elif (homedir and isdir(homedir) and homedir not in ['/']):
235 conf_dir = join(homedir, '.config', DIRNAME)
236 # Create conf_dir if necessary
237 if not isdir(conf_dir):
239 chmod(conf_dir, 0o700)
240 self.conf_file = join(conf_dir, CONF_FILE)
242 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
243 self.log.error('Please use "--config" to locate the conf file')
246 self.db_file = join(data_dir, 'sima.db')
248 config = configparser.SafeConfigParser()
249 # If no conf file present, uses defaults
250 if not isfile(self.conf_file):
254 self.log.info('Loading configuration from: %s' % self.conf_file)
258 config.read(self.conf_file)
266 # vim: ai ts=4 sw=4 sts=4 expandtab