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",
64 'queue_mode': "track", #TODO control values
65 'single_album': "false",
71 'flavour': "sensible", # in pure, sensible, genre
78 class ConfMan(object): # CONFIG MANAGER CLASS
80 Configuration manager.
81 Default configuration is stored in DEFAULT_CONF dictionnary.
82 First init_config() run to get config from file.
83 Then control_conf() is run and retrieve configuration from defaults if not
85 These settings are then updated with command line options with
86 supersedes_config_with_cmd_line_options().
88 Order of priority for the origin of an option is then (lowest to highest):
90 * Env. Var for MPD host, port and password
91 * configuration file (overrides previous)
92 * command line options (overrides previous)
95 def __init__(self, logger, options=None):
96 # options settings priority:
97 # defauts < conf. file < command line
98 self.conf_file = options.get('conf_file')
100 self.defaults = dict(DEFAULT_CONF)
101 self.startopt = options
110 self.supersedes_config_with_cmd_line_options()
111 self.config['sima']['db_file'] = self.db_file
115 self.config.getboolean('MPD', 'password')
116 self.log.debug('No password set, proceeding without ' +
120 # ValueError if password not a boolean, hence an actual password.
121 pwd = self.config.get('MPD', 'password')
123 self.log.debug('Password set as an empty string.')
127 def control_mod(self):
129 Controls conf file permissions.
131 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
132 self.log.debug('file permission is: %o' % mode)
133 if mode & S_IRWXO or mode & S_IRWXG:
134 self.log.warning('File is readable by "other" and/or' +
135 ' "group" (actual permission %o octal).' %
137 self.log.warning('Consider setting permissions' +
140 def supersedes_config_with_cmd_line_options(self):
141 """Updates defaults settings with command line options"""
142 for sec in self.config.sections():
143 for opt in self.config.options(sec):
144 if opt in list(self.startopt.keys()):
145 self.config.set(sec, opt, str(self.startopt.get(opt)))
148 """Use MPD en.var. to set defaults"""
149 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
151 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
152 self.defaults['MPD']['host'] = mpd_host
154 self.log.info('Env. variable MPD_HOST contains password.')
155 self.defaults['MPD']['password'] = passwd
157 self.log.info('Env. variable MPD_PORT set to "%s".'
159 self.defaults['MPD']['port'] = mpd_port
161 def control_conf(self):
162 """Get through options/values and set defaults if not in conf file."""
163 # Control presence of obsolete settings
164 for option in ['history', 'history_length', 'top_tracks']:
165 if self.config.has_option('sima', option):
166 self.log.warning('Obsolete setting found in conf file: "%s"'
168 # Setting default if not specified
169 for section in DEFAULT_CONF.keys():
170 if section not in self.config.sections():
171 self.log.debug('[%s] NOT in conf file' % section)
172 self.config.add_section(section)
173 for option in self.defaults[section]:
174 self.config.set(section,
176 self.defaults[section][option])
178 'Setting option with default value: %s = %s' %
179 (option, self.defaults[section][option]))
180 elif section in self.config.sections():
181 self.log.debug('[%s] present in conf file' % section)
182 for option in self.defaults[section]:
183 if self.config.has_option(section, option):
184 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
185 # (option, self.config.get(section, option)))
189 'Option "%s" missing in section "%s"' %
191 self.log.debug('=> setting default "%s" (may not suit you…)' %
192 self.defaults[section][option])
193 self.config.set(section, option,
194 self.defaults[section][option])
196 def init_config(self):
198 Use XDG directory standard if exists
199 else use "HOME/(.config|.local/share)/sima/"
200 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
203 homedir = environ.get('HOME')
205 if environ.get('XDG_DATA_HOME'):
206 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
207 elif self.startopt.get('var_dir'):
208 # If var folder is provided via CLI set data_dir accordingly
209 data_dir = join(self.startopt.get('var_dir'))
210 elif (homedir and isdir(homedir) and homedir not in ['/']):
211 data_dir = join(homedir, '.local', 'share', DIRNAME)
213 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
214 self.log.error('Please use "--var_dir" to set a proper location')
217 if not isdir(data_dir):
219 chmod(data_dir, 0o700)
221 if self.startopt.get('conf_file'):
222 # No need to handle conf file location
224 elif environ.get('XDG_CONFIG_HOME'):
225 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
226 elif (homedir and isdir(homedir) and homedir not in ['/']):
227 conf_dir = join(homedir, '.config', DIRNAME)
228 # Create conf_dir if necessary
229 if not isdir(conf_dir):
231 chmod(conf_dir, 0o700)
232 self.conf_file = join(conf_dir, CONF_FILE)
234 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
235 self.log.error('Please use "--config" to locate the conf file')
238 self.db_file = join(data_dir, 'sima.db')
240 config = configparser.SafeConfigParser()
241 # If no conf file present, uses defaults
242 if not isfile(self.conf_file):
246 self.log.info('Loading configuration from: %s' % self.conf_file)
250 config.read(self.conf_file)
258 # vim: ai ts=4 sw=4 sts=4 expandtab