# -*- coding: utf-8 -*-
-
-# Copyright (c) 2009, 2010, 2011, 2013 Jack Kaliko <kaliko@azylum.org>
+# Copyright (c) 2009, 2010, 2011, 2013, 2014, 2015 Jack Kaliko <kaliko@azylum.org>
#
# This file is part of sima
#
# IMPORTS
import configparser
+import logging
import sys
from configparser import Error
-from os import (makedirs, environ, stat, chmod)
-from os.path import (join, isdir, isfile)
+from os import (access, makedirs, environ, stat, chmod, W_OK, R_OK)
+from os.path import (join, isdir, isfile, dirname, exists)
from stat import (S_IMODE, ST_MODE, S_IRWXO, S_IRWXG)
from . import utils
# DEFAULTS
-DIRNAME = 'sima'
-CONF_FILE = 'sima.cfg'
+DIRNAME = 'mpd_sima'
+CONF_FILE = 'mpd_sima.cfg'
DEFAULT_CONF = {
'MPD': {
'host': "localhost",
#'password': "",
- 'port': "6600",
+ 'port': 6600,
},
'sima': {
- 'internal': "Crop, History, MpdOptions, Lastfm, RandomFallBack",
+ 'internal': "Crop, Lastfm, Random",
'contrib': "",
'user_db': "false",
- 'history_duration': "8",
- 'queue_length': "1",
+ 'history_duration': 8,
+ 'queue_length': 2,
+ 'var_dir': 'empty',
+ 'musicbrainzid': "true",
},
'daemon':{
- 'daemon': "false",
+ 'daemon': False,
'pidfile': "",
},
'log': {
'verbosity': "info",
'logfile': "",
},
+ 'crop': {
+ 'consume': 10,
+ 'priority': 0,
+ },
'echonest': {
+ 'queue_mode': "track", #TODO control values
+ 'max_art': 15,
+ 'single_album': "false",
+ 'track_to_add': 1,
+ 'album_to_add': 1,
+ 'depth': 1,
+ 'priority': 100,
},
'lastfm': {
- 'dynamic': "10",
- 'similarity': "15",
'queue_mode': "track", #TODO control values
+ 'max_art': 10,
'single_album': "false",
- 'track_to_add': "1",
- 'album_to_add': "1",
- 'depth': "1",
+ 'track_to_add': 1,
+ 'album_to_add': 1,
+ 'depth': 1,
+ 'cache': True,
+ 'priority': 100,
+ },
+ 'random': {
+ 'flavour': "sensible", # in pure, sensible
+ 'track_to_add': 1,
+ 'priority': 50,
},
- 'randomfallback': {
- 'flavour': "sensible", # in pure, sensible, genre
- 'track_to_add': "1",
- }
}
#
* command line options (overrides previous)
"""
- def __init__(self, logger, options=None):
+ def __init__(self, options=None):
+ self.log = logging.getLogger('sima')
# options settings priority:
- # defauts < conf. file < command line
+ # defauts < env. var. < conf. file < command line
self.conf_file = options.get('conf_file')
- self.config = None
- self.defaults = dict(DEFAULT_CONF)
+ self.config = configparser.ConfigParser(inline_comment_prefixes='#')
+ self.config.read_dict(DEFAULT_CONF)
+ # update DEFAULT_CONF with env. var.
+ self.use_envar()
self.startopt = options
- ## Sima sqlite DB
- self.db_file = None
- self.log = logger
## INIT CALLS
- self.use_envar()
self.init_config()
- self.control_conf()
self.supersedes_config_with_cmd_line_options()
- self.config['sima']['db_file'] = self.db_file
+ # Controls files access
+ self.control_facc()
+ # set dbfile
+ self.config['sima']['db_file'] = join(self.config['sima']['var_dir'], 'sima.db')
- def get_pw(self):
- try:
- self.config.getboolean('MPD', 'password')
- self.log.debug('No password set, proceeding without ' +
- 'authentication...')
- return None
- except ValueError:
- # ValueError if password not a boolean, hence an actual password.
- pwd = self.config.get('MPD', 'password')
- if not pwd:
- self.log.debug('Password set as an empty string.')
- return None
- return pwd
+ # Create directories
+ data_dir = self.config['sima']['var_dir']
+ if not isdir(data_dir):
+ self.log.trace('Creating "{}"'.format(data_dir))
+ makedirs(data_dir)
+ chmod(data_dir, 0o700)
+
+ def control_facc(self):
+ """Controls file access.
+ This is relevant only for file provided through the configuration file
+ since files provided on the command line are already checked with
+ argparse.
+ """
+ ok = True
+ for op, ftochk in [('logfile', self.config.get('log','logfile')),
+ ('pidfile', self.config.get('daemon', 'pidfile')),]:
+ if not ftochk:
+ continue
+ if isdir(ftochk):
+ self.log.critical('Need a file not a directory: "{}"'.format(ftochk))
+ ok = False
+ if not exists(ftochk):
+ # Is parent directory writable then
+ filedir = dirname(ftochk)
+ if not access(filedir, W_OK):
+ self.log.critical('no write access to "{0}" ({1})'.format(filedir, op))
+ ok = False
+ else:
+ if not access(ftochk, W_OK):
+ self.log.critical('no write access to "{0}" ({1})'.format(ftochk, op))
+ ok = False
+ if not ok:
+ if exists(self.conf_file):
+ self.log.warning('Try to check the configuration file: {}'.format(self.conf_file))
+ sys.exit(2)
def control_mod(self):
"""
mpd_host, mpd_port, passwd = utils.get_mpd_environ()
if mpd_host:
self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
- self.defaults['MPD']['host'] = mpd_host
+ self.config['MPD'].update(host=mpd_host)
if passwd:
self.log.info('Env. variable MPD_HOST contains password.')
- self.defaults['MPD']['password'] = passwd
+ self.config['MPD'].update(password=passwd)
if mpd_port:
- self.log.info('Env. variable MPD_PORT set to "%s".'
- % mpd_port)
- self.defaults['MPD']['port'] = mpd_port
-
- def control_conf(self):
- """Get through options/values and set defaults if not in conf file."""
- # Control presence of obsolete settings
- for option in ['history', 'history_length', 'top_tracks']:
- if self.config.has_option('sima', option):
- self.log.warning('Obsolete setting found in conf file: "%s"'
- % option)
- # Setting default if not specified
- for section in DEFAULT_CONF.keys():
- if section not in self.config.sections():
- self.log.debug('[%s] NOT in conf file' % section)
- self.config.add_section(section)
- for option in self.defaults[section]:
- self.config.set(section,
- option,
- self.defaults[section][option])
- self.log.debug(
- 'Setting option with default value: %s = %s' %
- (option, self.defaults[section][option]))
- elif section in self.config.sections():
- self.log.debug('[%s] present in conf file' % section)
- for option in self.defaults[section]:
- if self.config.has_option(section, option):
- #self.log.debug(u'option "%s" set to "%s" in conf. file' %
- # (option, self.config.get(section, option)))
- pass
- else:
- self.log.debug(
- 'Option "%s" missing in section "%s"' %
- (option, section))
- self.log.debug('=> setting default "%s" (may not suit you…)' %
- self.defaults[section][option])
- self.config.set(section, option,
- self.defaults[section][option])
+ self.log.info('Env. variable MPD_PORT set to "%s".' % mpd_port)
+ self.config['MPD'].update(port=mpd_port)
def init_config(self):
"""
if environ.get('XDG_DATA_HOME'):
data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
- elif self.startopt.get('var_dir'):
- # If var folder is provided via CLI set data_dir accordingly
- data_dir = join(self.startopt.get('var_dir'))
- elif (homedir and isdir(homedir) and homedir not in ['/']):
+ elif homedir and isdir(homedir) and homedir not in ['/']:
data_dir = join(homedir, '.local', 'share', DIRNAME)
else:
- self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
- self.log.error('Please use "--var_dir" to set a proper location')
+ self.log.critical('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
+ self.log.critical('Please use "--var-dir" to set a proper location')
sys.exit(1)
- if not isdir(data_dir):
- makedirs(data_dir)
- chmod(data_dir, 0o700)
-
if self.startopt.get('conf_file'):
# No need to handle conf file location
pass
elif environ.get('XDG_CONFIG_HOME'):
conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
- elif (homedir and isdir(homedir) and homedir not in ['/']):
+ elif homedir and isdir(homedir) and homedir not in ['/']:
conf_dir = join(homedir, '.config', DIRNAME)
- # Create conf_dir if necessary
- if not isdir(conf_dir):
- makedirs(conf_dir)
- chmod(conf_dir, 0o700)
self.conf_file = join(conf_dir, CONF_FILE)
else:
- self.log.error('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
- self.log.error('Please use "--config" to locate the conf file')
+ self.log.critical('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
+ self.log.critical('Please use "--config" to locate the conf file')
sys.exit(1)
- self.db_file = join(data_dir, 'sima.db')
+ ## Sima sqlite DB
+ self.config['sima']['var_dir'] = join(data_dir)
- config = configparser.SafeConfigParser()
# If no conf file present, uses defaults
if not isfile(self.conf_file):
- self.config = config
return
self.log.info('Loading configuration from: %s' % self.conf_file)
self.control_mod()
try:
- config.read(self.conf_file)
+ self.config.read(self.conf_file)
except Error as err:
self.log.error(err)
sys.exit(1)
- self.config = config
-
# VIM MODLINE
# vim: ai ts=4 sw=4 sts=4 expandtab