1 # -*- coding: utf-8 -*-
2 # Copyright (c) 2009, 2010, 2011, 2013, 2014, 2015 Jack Kaliko <kaliko@azylum.org>
4 # This file is part of sima
6 # sima is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # sima is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with sima. If not, see <http://www.gnu.org/licenses/>.
19 # pylint: disable=bad-continuation
22 Deal with configuration and data files.
23 Parse configuration file and set defaults for missing options.
31 from configparser import Error
32 from os import (access, makedirs, environ, stat, chmod, W_OK)
33 from os.path import (join, isdir, isfile, dirname, exists)
34 from stat import (S_IMODE, ST_MODE, S_IRWXO, S_IRWXG)
40 CONF_FILE = 'mpd_sima.cfg'
49 'internal': "Crop, Lastfm, Random",
52 'history_duration': 8,
55 'musicbrainzid': "true",
70 'queue_mode': "track", #TODO control values
72 'single_album': "false",
80 'flavour': "sensible", # in pure, sensible
88 class ConfMan(object): # CONFIG MANAGER CLASS
90 Configuration manager.
91 Default configuration is stored in DEFAULT_CONF dictionnary.
92 First init_config() run to get config from file.
93 Then control_conf() is run and retrieve configuration from defaults if not
95 These settings are then updated with command line options with
96 supersedes_config_with_cmd_line_options().
98 Order of priority for the origin of an option is then (lowest to highest):
100 * Env. Var for MPD host, port and password
101 * configuration file (overrides previous)
102 * command line options (overrides previous)
105 def __init__(self, options=None):
106 self.log = logging.getLogger('sima')
107 # options settings priority:
108 # defauts < env. var. < conf. file < command line
109 self.conf_file = options.get('conf_file')
110 self.config = configparser.ConfigParser(inline_comment_prefixes='#')
111 self.config.read_dict(DEFAULT_CONF)
112 # update DEFAULT_CONF with env. var.
114 self.startopt = options
118 self.supersedes_config_with_cmd_line_options()
119 # Controls files access
122 self.config['sima']['db_file'] = join(self.config['sima']['var_dir'], 'sima.db')
125 data_dir = self.config['sima']['var_dir']
126 if not isdir(data_dir):
127 self.log.trace('Creating "{}"'.format(data_dir))
129 chmod(data_dir, 0o700)
131 def control_facc(self):
132 """Controls file access.
133 This is relevant only for file provided through the configuration file
134 since files provided on the command line are already checked with
138 for op, ftochk in [('logfile', self.config.get('log', 'logfile')),
139 ('pidfile', self.config.get('daemon', 'pidfile')),]:
143 self.log.critical('Need a file not a directory: "%s"', ftochk)
145 if not exists(ftochk):
146 # Is parent directory writable then
147 filedir = dirname(ftochk)
148 if not access(filedir, W_OK):
149 self.log.critical('no write access to "%s" (%s)', filedir, op)
152 if not access(ftochk, W_OK):
153 self.log.critical('no write access to "%s" (%s)', ftochk, op)
156 if exists(self.conf_file):
157 self.log.warning('Try to check the configuration file: %s', self.conf_file)
160 def control_mod(self):
162 Controls conf file permissions.
164 mode = S_IMODE(stat(self.conf_file)[ST_MODE])
165 self.log.debug('file permission is: %o', mode)
166 if mode & S_IRWXO or mode & S_IRWXG:
167 self.log.warning('File is readable by "other" and/or' +
168 ' "group" (actual permission %o octal).' %
170 self.log.warning('Consider setting permissions' +
173 def supersedes_config_with_cmd_line_options(self):
174 """Updates defaults settings with command line options"""
175 for sec in self.config.sections():
176 for opt in self.config.options(sec):
177 if opt in list(self.startopt.keys()):
178 self.config.set(sec, opt, str(self.startopt.get(opt)))
181 """Use MPD en.var. to set defaults"""
182 mpd_host, mpd_port, passwd = utils.get_mpd_environ()
184 self.log.info('Env. variable MPD_HOST set to "%s"', mpd_host)
185 self.config['MPD'].update(host=mpd_host)
187 self.log.info('Env. variable MPD_HOST contains password.')
188 self.config['MPD'].update(password=passwd)
190 self.log.info('Env. variable MPD_PORT set to "%s".', mpd_port)
191 self.config['MPD'].update(port=mpd_port)
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 homedir and isdir(homedir) and homedir not in ['/']:
205 data_dir = join(homedir, '.local', 'share', DIRNAME)
207 self.log.critical('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
208 self.log.critical('Please use "--var-dir" to set a proper location')
211 if self.startopt.get('conf_file'):
212 # No need to handle conf file location
214 elif environ.get('XDG_CONFIG_HOME'):
215 conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
216 elif homedir and isdir(homedir) and homedir not in ['/']:
217 conf_dir = join(homedir, '.config', DIRNAME)
218 self.conf_file = join(conf_dir, CONF_FILE)
220 self.log.critical('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
221 self.log.critical('Please use "--config" to locate the conf file')
225 self.config['sima']['var_dir'] = join(data_dir)
227 # If no conf file present, uses defaults
228 if not isfile(self.conf_file):
231 self.log.info('Loading configuration from: %s', self.conf_file)
235 self.config.read(self.conf_file)
241 # vim: ai ts=4 sw=4 sts=4 expandtab