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'
50 'queue_mode': "track", #TODO control values
52 'history_duration': "8",
57 'single_album': "false",
58 'check_new_version':"false",},
67 class ConfMan(object): # CONFIG MANAGER CLASS
69 Configuration manager.
70 Default configuration is stored in DEFAULT_CONF dictionnary.
71 First init_config() run to get config from file.
72 Then control_conf() is run and retrieve configuration from defaults if not
74 These settings are then updated with command line options with
75 supersedes_config_with_cmd_line_options().
77 Order of priority for the origin of an option is then (lowest to highest):
79 * Env. Var for MPD host, port and password
80 * configuration file (overrides previous)
81 * command line options (overrides previous)
84 def __init__(self, logger, options=None):
85 # options settings priority:
86 # defauts < conf. file < command line
87 self.conf_file = options.get('conf_file')
89 self.defaults = dict(DEFAULT_CONF)
90 self.startopt = options
99 self.supersedes_config_with_cmd_line_options()
103 self.config.getboolean('MPD', 'password')
104 self.log.debug('No password set, proceeding without ' +
108 # ValueError if password not a boolean, hence an actual password.
109 pw = self.config.get('MPD', 'password')
111 self.log.debug('Password set as an empty string.')
115 def control_mod(self):
117 Controls conf file permissions.
119 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
120 self.log.debug('file permission is: %o' % mode)
121 if mode & S_IRWXO or mode & S_IRWXG:
122 self.log.warning('File is readable by "other" and/or' +
123 ' "group" (actual permission %o octal).' %
125 self.log.warning('Consider setting permissions' +
128 def supersedes_config_with_cmd_line_options(self):
129 """Updates defaults settings with command line options"""
130 for sec in self.config.sections():
131 for opt in self.config.options(sec):
132 if opt in list(self.startopt.keys()):
133 self.config.set(sec, opt, str(self.startopt.get(opt)))
136 """Use MPD en.var. to set defaults"""
137 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
139 self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
140 self.defaults['MPD']['host'] = mpd_host
142 self.log.info('Env. variable MPD_HOST contains password.')
143 self.defaults['MPD']['password'] = passwd
145 self.log.info('Env. variable MPD_PORT set to "%s".'
147 self.defaults['MPD']['port'] = mpd_port
149 def control_conf(self):
150 """Get through options/values and set defaults if not in conf file."""
151 # Control presence of obsolete settings
152 for option in ['history', 'history_length', 'top_tracks']:
153 if self.config.has_option('sima', option):
154 self.log.warning('Obsolete setting found in conf file: "%s"'
156 # Setting default if not specified
157 for section in DEFAULT_CONF.keys():
158 if section not in self.config.sections():
159 self.log.debug('[%s] NOT in conf file' % section)
160 self.config.add_section(section)
161 for option in self.defaults[section]:
162 self.config.set(section,
164 self.defaults[section][option])
166 'Setting option with default value: %s = %s' %
167 (option, self.defaults[section][option]))
168 elif section in self.config.sections():
169 self.log.debug('[%s] present in conf file' % section)
170 for option in self.defaults[section]:
171 if self.config.has_option(section, option):
172 #self.log.debug(u'option "%s" set to "%s" in conf. file' %
173 # (option, self.config.get(section, option)))
177 'Option "%s" missing in section "%s"' %
179 self.log.debug('=> setting default "%s" (may not suit you…)' %
180 self.defaults[section][option])
181 self.config.set(section, option,
182 self.defaults[section][option])
184 def init_config(self):
186 Use XDG directory standard if exists
187 else use "HOME/(.config|.local/share)/sima/"
188 http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
191 homedir = environ.get('HOME')
193 if environ.get('XDG_DATA_HOME'):
194 data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
195 elif self.startopt.get('var_dir'):
196 # If var folder is provided via CLI set data_dir accordingly
197 data_dir = join(self.startopt.get('var_dir'))
198 elif (homedir and isdir(homedir) and homedir not in ['/']):
199 data_dir = join(homedir, '.local', 'share', DIRNAME)
201 self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
202 self.log.error('Please use "--var_dir" to set a proper location')
205 if not isdir(data_dir):
207 chmod(data_dir, 0o700)
209 if self.startopt.get('conf_file'):
210 # No need to handle conf file location
212 elif environ.get('XDG_CONFIG_HOME'):
213 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
214 elif (homedir and isdir(homedir) and homedir not in ['/']):
215 conf_dir = join(homedir, '.config', DIRNAME)
216 # Create conf_dir if necessary
217 if not isdir(conf_dir):
219 chmod(conf_dir, 0o700)
220 self.conf_file = join(conf_dir, CONF_FILE)
222 self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
223 self.log.error('Please use "--config" to locate the conf file')
226 self.db_file = join(data_dir, 'sima.db')
228 config = configparser.SafeConfigParser()
230 # If no conf file present, uses defaults
231 if not isfile(self.conf_file):
235 self.log.info('Loading configuration from: %s' % self.conf_file)
239 config.read(self.conf_file)
247 # vim: ai ts=4 sw=4 sts=4 expandtab