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, History, MpdOptions, Lastfm, RandomFallBack",
52 'history_duration': "8",
68 'queue_mode': "track", #TODO control values
69 'single_album': "false",
75 'flavour': "sensible", # in pure, sensible, genre
82 class ConfMan(object): # CONFIG MANAGER CLASS
84 Configuration manager.
85 Default configuration is stored in DEFAULT_CONF dictionnary.
86 First init_config() run to get config from file.
87 Then control_conf() is run and retrieve configuration from defaults if not
89 These settings are then updated with command line options with
90 supersedes_config_with_cmd_line_options().
92 Order of priority for the origin of an option is then (lowest to highest):
94 * Env. Var for MPD host, port and password
95 * configuration file (overrides previous)
96 * command line options (overrides previous)
99 def __init__(self, logger, options=None):
100 # options settings priority:
101 # defauts < conf. file < command line
102 self.conf_file = options.get('conf_file')
104 self.defaults = dict(DEFAULT_CONF)
105 self.startopt = options
114 self.supersedes_config_with_cmd_line_options()
115 self.config['sima']['db_file'] = self.db_file
119 self.config.getboolean('MPD', 'password')
120 self.log.debug('No password set, proceeding without ' +
124 # ValueError if password not a boolean, hence an actual password.
125 pwd = self.config.get('MPD', 'password')
127 self.log.debug('Password set as an empty string.')
131 def control_mod(self):
133 Controls conf file permissions.
135 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
136 self.log.debug('file permission is: %o' % mode)
137 if mode & S_IRWXO or mode & S_IRWXG:
138 self.log.warning('File is readable by "other" and/or' +
139 ' "group" (actual permission %o octal).' %
141 self.log.warning('Consider setting permissions' +
144 def supersedes_config_with_cmd_line_options(self):
145 """Updates defaults settings with command line options"""
146 for sec in self.config.sections():
147 for opt in self.config.options(sec):
148 if opt in list(self.startopt.keys()):
149 self.config.set(sec, opt, str(self.startopt.get(opt)))
152 """Use MPD en.var. to set defaults"""
153 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
155 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
156 self.defaults['MPD']['host'] = mpd_host
158 self.log.info('Env. variable MPD_HOST contains password.')
159 self.defaults['MPD']['password'] = passwd
161 self.log.info('Env. variable MPD_PORT set to "%s".'
163 self.defaults['MPD']['port'] = mpd_port
165 def control_conf(self):
166 """Get through options/values and set defaults if not in conf file."""
167 # Control presence of obsolete settings
168 for option in ['history', 'history_length', 'top_tracks']:
169 if self.config.has_option('sima', option):
170 self.log.warning('Obsolete setting found in conf file: "%s"'
172 # Setting default if not specified
173 for section in DEFAULT_CONF.keys():
174 if section not in self.config.sections():
175 self.log.debug('[%s] NOT in conf file' % section)
176 self.config.add_section(section)
177 for option in self.defaults[section]:
178 self.config.set(section,
180 self.defaults[section][option])
182 'Setting option with default value: %s = %s' %
183 (option, self.defaults[section][option]))
184 elif section in self.config.sections():
185 self.log.debug('[%s] present in conf file' % section)
186 for option in self.defaults[section]:
187 if self.config.has_option(section, option):
188 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
189 # (option, self.config.get(section, option)))
193 'Option "%s" missing in section "%s"' %
195 self.log.debug('=> setting default "%s" (may not suit you…)' %
196 self.defaults[section][option])
197 self.config.set(section, option,
198 self.defaults[section][option])
200 def init_config(self):
202 Use XDG directory standard if exists
203 else use "HOME/(.config|.local/share)/sima/"
204 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
207 homedir = environ.get('HOME')
209 if environ.get('XDG_DATA_HOME'):
210 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
211 elif self.startopt.get('var_dir'):
212 # If var folder is provided via CLI set data_dir accordingly
213 data_dir = join(self.startopt.get('var_dir'))
214 elif (homedir and isdir(homedir) and homedir not in ['/']):
215 data_dir = join(homedir, '.local', 'share', DIRNAME)
217 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
218 self.log.error('Please use "--var_dir" to set a proper location')
221 if not isdir(data_dir):
223 chmod(data_dir, 0o700)
225 if self.startopt.get('conf_file'):
226 # No need to handle conf file location
228 elif environ.get('XDG_CONFIG_HOME'):
229 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
230 elif (homedir and isdir(homedir) and homedir not in ['/']):
231 conf_dir = join(homedir, '.config', DIRNAME)
232 # Create conf_dir if necessary
233 if not isdir(conf_dir):
235 chmod(conf_dir, 0o700)
236 self.conf_file = join(conf_dir, CONF_FILE)
238 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
239 self.log.error('Please use "--config" to locate the conf file')
242 self.db_file = join(data_dir, 'sima.db')
244 config = configparser.SafeConfigParser()
245 # If no conf file present, uses defaults
246 if not isfile(self.conf_file):
250 self.log.info('Loading configuration from: %s' % self.conf_file)
254 config.read(self.conf_file)
262 # vim: ai ts=4 sw=4 sts=4 expandtab