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'
48 'internal': "Crop, History, MpdOptions, Lastfm, RandomFallBack",
51 'history_duration': "8",
66 'queue_mode': "track", #TODO control values
67 'single_album': "false",
73 'flavour': "sensible", # in pure, sensible, genre
80 class ConfMan(object): # CONFIG MANAGER CLASS
82 Configuration manager.
83 Default configuration is stored in DEFAULT_CONF dictionnary.
84 First init_config() run to get config from file.
85 Then control_conf() is run and retrieve configuration from defaults if not
87 These settings are then updated with command line options with
88 supersedes_config_with_cmd_line_options().
90 Order of priority for the origin of an option is then (lowest to highest):
92 * Env. Var for MPD host, port and password
93 * configuration file (overrides previous)
94 * command line options (overrides previous)
97 def __init__(self, logger, options=None):
98 # options settings priority:
99 # defauts < conf. file < command line
100 self.conf_file = options.get('conf_file')
102 self.defaults = dict(DEFAULT_CONF)
103 self.startopt = options
112 self.supersedes_config_with_cmd_line_options()
113 self.config['sima']['db_file'] = self.db_file
117 self.config.getboolean('MPD', 'password')
118 self.log.debug('No password set, proceeding without ' +
122 # ValueError if password not a boolean, hence an actual password.
123 pwd = self.config.get('MPD', 'password')
125 self.log.debug('Password set as an empty string.')
129 def control_mod(self):
131 Controls conf file permissions.
133 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
134 self.log.debug('file permission is: %o' % mode)
135 if mode & S_IRWXO or mode & S_IRWXG:
136 self.log.warning('File is readable by "other" and/or' +
137 ' "group" (actual permission %o octal).' %
139 self.log.warning('Consider setting permissions' +
142 def supersedes_config_with_cmd_line_options(self):
143 """Updates defaults settings with command line options"""
144 for sec in self.config.sections():
145 for opt in self.config.options(sec):
146 if opt in list(self.startopt.keys()):
147 self.config.set(sec, opt, str(self.startopt.get(opt)))
150 """Use MPD en.var. to set defaults"""
151 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
153 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
154 self.defaults['MPD']['host'] = mpd_host
156 self.log.info('Env. variable MPD_HOST contains password.')
157 self.defaults['MPD']['password'] = passwd
159 self.log.info('Env. variable MPD_PORT set to "%s".'
161 self.defaults['MPD']['port'] = mpd_port
163 def control_conf(self):
164 """Get through options/values and set defaults if not in conf file."""
165 # Control presence of obsolete settings
166 for option in ['history', 'history_length', 'top_tracks']:
167 if self.config.has_option('sima', option):
168 self.log.warning('Obsolete setting found in conf file: "%s"'
170 # Setting default if not specified
171 for section in DEFAULT_CONF.keys():
172 if section not in self.config.sections():
173 self.log.debug('[%s] NOT in conf file' % section)
174 self.config.add_section(section)
175 for option in self.defaults[section]:
176 self.config.set(section,
178 self.defaults[section][option])
180 'Setting option with default value: %s = %s' %
181 (option, self.defaults[section][option]))
182 elif section in self.config.sections():
183 self.log.debug('[%s] present in conf file' % section)
184 for option in self.defaults[section]:
185 if self.config.has_option(section, option):
186 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
187 # (option, self.config.get(section, option)))
191 'Option "%s" missing in section "%s"' %
193 self.log.debug('=> setting default "%s" (may not suit you…)' %
194 self.defaults[section][option])
195 self.config.set(section, option,
196 self.defaults[section][option])
198 def init_config(self):
200 Use XDG directory standard if exists
201 else use "HOME/(.config|.local/share)/sima/"
202 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
205 homedir = environ.get('HOME')
207 if environ.get('XDG_DATA_HOME'):
208 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
209 elif self.startopt.get('var_dir'):
210 # If var folder is provided via CLI set data_dir accordingly
211 data_dir = join(self.startopt.get('var_dir'))
212 elif (homedir and isdir(homedir) and homedir not in ['/']):
213 data_dir = join(homedir, '.local', 'share', DIRNAME)
215 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
216 self.log.error('Please use "--var_dir" to set a proper location')
219 if not isdir(data_dir):
221 chmod(data_dir, 0o700)
223 if self.startopt.get('conf_file'):
224 # No need to handle conf file location
226 elif environ.get('XDG_CONFIG_HOME'):
227 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
228 elif (homedir and isdir(homedir) and homedir not in ['/']):
229 conf_dir = join(homedir, '.config', DIRNAME)
230 # Create conf_dir if necessary
231 if not isdir(conf_dir):
233 chmod(conf_dir, 0o700)
234 self.conf_file = join(conf_dir, CONF_FILE)
236 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
237 self.log.error('Please use "--config" to locate the conf file')
240 self.db_file = join(data_dir, 'sima.db')
242 config = configparser.SafeConfigParser()
243 # If no conf file present, uses defaults
244 if not isfile(self.conf_file):
248 self.log.info('Loading configuration from: %s' % self.conf_file)
252 config.read(self.conf_file)
260 # vim: ai ts=4 sw=4 sts=4 expandtab