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",
61 'queue_mode': "track", #TODO control values
62 'single_album': "false",
68 'flavour': "sensible", # in pure, sensible, genre
75 class ConfMan(object): # CONFIG MANAGER CLASS
77 Configuration manager.
78 Default configuration is stored in DEFAULT_CONF dictionnary.
79 First init_config() run to get config from file.
80 Then control_conf() is run and retrieve configuration from defaults if not
82 These settings are then updated with command line options with
83 supersedes_config_with_cmd_line_options().
85 Order of priority for the origin of an option is then (lowest to highest):
87 * Env. Var for MPD host, port and password
88 * configuration file (overrides previous)
89 * command line options (overrides previous)
92 def __init__(self, logger, options=None):
93 # options settings priority:
94 # defauts < conf. file < command line
95 self.conf_file = options.get('conf_file')
97 self.defaults = dict(DEFAULT_CONF)
98 self.startopt = options
107 self.supersedes_config_with_cmd_line_options()
108 self.config['sima']['db_file'] = self.db_file
112 self.config.getboolean('MPD', 'password')
113 self.log.debug('No password set, proceeding without ' +
117 # ValueError if password not a boolean, hence an actual password.
118 pw = self.config.get('MPD', 'password')
120 self.log.debug('Password set as an empty string.')
124 def control_mod(self):
126 Controls conf file permissions.
128 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
129 self.log.debug('file permission is: %o' % mode)
130 if mode & S_IRWXO or mode & S_IRWXG:
131 self.log.warning('File is readable by "other" and/or' +
132 ' "group" (actual permission %o octal).' %
134 self.log.warning('Consider setting permissions' +
137 def supersedes_config_with_cmd_line_options(self):
138 """Updates defaults settings with command line options"""
139 for sec in self.config.sections():
140 for opt in self.config.options(sec):
141 if opt in list(self.startopt.keys()):
142 self.config.set(sec, opt, str(self.startopt.get(opt)))
145 """Use MPD en.var. to set defaults"""
146 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
148 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
149 self.defaults['MPD']['host'] = mpd_host
151 self.log.info('Env. variable MPD_HOST contains password.')
152 self.defaults['MPD']['password'] = passwd
154 self.log.info('Env. variable MPD_PORT set to "%s".'
156 self.defaults['MPD']['port'] = mpd_port
158 def control_conf(self):
159 """Get through options/values and set defaults if not in conf file."""
160 # Control presence of obsolete settings
161 for option in ['history', 'history_length', 'top_tracks']:
162 if self.config.has_option('sima', option):
163 self.log.warning('Obsolete setting found in conf file: "%s"'
165 # Setting default if not specified
166 for section in DEFAULT_CONF.keys():
167 if section not in self.config.sections():
168 self.log.debug('[%s] NOT in conf file' % section)
169 self.config.add_section(section)
170 for option in self.defaults[section]:
171 self.config.set(section,
173 self.defaults[section][option])
175 'Setting option with default value: %s = %s' %
176 (option, self.defaults[section][option]))
177 elif section in self.config.sections():
178 self.log.debug('[%s] present in conf file' % section)
179 for option in self.defaults[section]:
180 if self.config.has_option(section, option):
181 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
182 # (option, self.config.get(section, option)))
186 'Option "%s" missing in section "%s"' %
188 self.log.debug('=> setting default "%s" (may not suit you…)' %
189 self.defaults[section][option])
190 self.config.set(section, option,
191 self.defaults[section][option])
193 def init_config(self):
195 Use XDG directory standard if exists
196 else use "HOME/(.config|.local/share)/sima/"
197 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
200 homedir = environ.get('HOME')
202 if environ.get('XDG_DATA_HOME'):
203 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
204 elif self.startopt.get('var_dir'):
205 # If var folder is provided via CLI set data_dir accordingly
206 data_dir = join(self.startopt.get('var_dir'))
207 elif (homedir and isdir(homedir) and homedir not in ['/']):
208 data_dir = join(homedir, '.local', 'share', DIRNAME)
210 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
211 self.log.error('Please use "--var_dir" to set a proper location')
214 if not isdir(data_dir):
216 chmod(data_dir, 0o700)
218 if self.startopt.get('conf_file'):
219 # No need to handle conf file location
221 elif environ.get('XDG_CONFIG_HOME'):
222 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
223 elif (homedir and isdir(homedir) and homedir not in ['/']):
224 conf_dir = join(homedir, '.config', DIRNAME)
225 # Create conf_dir if necessary
226 if not isdir(conf_dir):
228 chmod(conf_dir, 0o700)
229 self.conf_file = join(conf_dir, CONF_FILE)
231 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
232 self.log.error('Please use "--config" to locate the conf file')
235 self.db_file = join(data_dir, 'sima.db')
237 config = configparser.SafeConfigParser()
238 # If no conf file present, uses defaults
239 if not isfile(self.conf_file):
243 self.log.info('Loading configuration from: %s' % self.conf_file)
247 config.read(self.conf_file)
255 # vim: ai ts=4 sw=4 sts=4 expandtab