# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
##
## Copyright (C) 2005-2011 Async Open Source
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation; either version 2
## of the License, or (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., or visit: http://www.gnu.org/.
##
##
## Author(s): Stoq Team <stoq-devel@async.com.br>
##
"""Routines for parsing the configuration file"""
import binascii
from ConfigParser import SafeConfigParser
import os
from stoqlib.lib.interfaces import IStoqConfig
from stoqlib.lib.osutils import get_application_dir
from stoqlib.lib.translation import stoqlib_gettext as _
from stoqlib.exceptions import (FilePermissionError,
NoConfigurationError)
_config = None
[docs]class StoqConfig:
domain = 'stoq'
def __init__(self):
self._config = SafeConfigParser()
self._settings = None
self.filename = None
def _get_config_file(self):
filename = self.domain + '.conf'
configdir = self.get_config_directory()
return os.path.join(configdir, filename)
def _open_config(self, filename):
if not os.path.exists(filename):
return False
self._config.read(filename)
return True
#
# Public API
#
[docs] def create(self):
config_dir = self.get_config_directory()
if not os.path.exists(config_dir):
os.mkdir(config_dir)
self.filename = os.path.join(
config_dir, StoqConfig.domain + '.conf')
[docs] def load_default(self):
"""
Loads default configuration file one will be loaded
"""
self.filename = self._get_config_file()
self.load(self.filename)
[docs] def load(self, filename):
"""
Loads the data from a configuration file
:param filename: filename
"""
if not filename:
raise TypeError("Missing filename option")
if not self._open_config(filename):
return
self.filename = filename
[docs] def load_settings(self, settings):
"""
Load data from a DatabaseSettings object
:param settings: the settings object
"""
self.set('General', 'logfile',
os.path.join(get_application_dir(StoqConfig.domain),
'application.log'))
self.set('Database', 'rdbms', settings.rdbms)
self.set('Database', 'address', settings.address)
self.set('Database', 'port', str(settings.port))
self.set('Database', 'dbname', settings.dbname)
self.set('Database', 'dbusername', settings.username)
if settings.password:
self.store_password(settings.password)
self._settings = settings
[docs] def flush(self):
"""
Writes the current configuration data to disk.
"""
if not self.filename:
self.filename = self._get_config_file()
with open(self.filename, 'w') as f:
self._config.write(f)
[docs] def get_filename(self):
config_dir = self.get_config_directory()
return os.path.join(config_dir, 'stoq.conf')
[docs] def get_config_directory(self):
return os.path.join(get_application_dir(self.domain))
[docs] def store_password(self, password):
configdir = self.get_config_directory()
datafile = os.path.join(configdir, 'data')
if not os.path.exists(datafile):
if not os.path.exists(configdir):
try:
os.makedirs(configdir)
os.chmod(configdir, 0700)
except OSError as e:
if e.errno == 13:
raise FilePermissionError(
"Could not " % configdir)
raise
try:
fd = open(datafile, "wb")
except OSError as e:
if e.errno == 13:
raise FilePermissionError("%s is not writable" % datafile)
raise
# obfuscate password to avoid it being easily identified when
# editing file on screen. this is *NOT* encryption!
fd.write(binascii.b2a_base64(password))
fd.close()
[docs] def get_settings(self):
if self._settings:
return self._settings
rdbms = self.get('Database', 'rdbms')
address = self.get('Database', 'address')
dbname = self.get('Database', 'dbname')
username = self.get('Database', 'dbusername')
port = self.get('Database', 'port')
if port:
port = int(port)
database_section = self.get('General', 'database_section')
if database_section is not None:
rdbms = self.get(database_section, 'rdbms') or rdbms
address = self.get(database_section, 'address') or address
dbname = self.get(database_section, 'dbname') or dbname
username = self.get(database_section, 'dbusername') or username
port = self.get(database_section, 'port') or port
# FIXME: This and load_settings() needs to be simplified now when
# we only have one global settings singleton
from stoqlib.database.settings import db_settings
db_settings.rdbms = rdbms or db_settings.rdbms
db_settings.address = address or db_settings.address
db_settings.port = port or db_settings.port
db_settings.dbname = dbname or db_settings.dbname
db_settings.username = username or db_settings.username
db_settings.password = db_settings.password
return db_settings
[docs] def set_from_options(self, options):
"""
Updates the configuration given a values instance
:param options: a optparse.Values instance
"""
from stoqlib.database.settings import db_settings
if options.address:
self.set('Database', 'address', options.address)
db_settings.address = options.address
if options.port:
self.set('Database', 'port', options.port)
db_settings.port = options.port
if options.dbname:
self.set('Database', 'dbname', options.dbname)
db_settings.dbname = options.dbname
if options.username:
self.set('Database', 'dbusername', options.username)
db_settings.username = options.username
if options.password:
self.store_password(options.password)
[docs] def set(self, section, option, value):
if not self.has_section(section):
self._config.add_section(section)
self._config.set(section, option, value)
[docs] def get(self, section, option):
if not self.has_section(section):
return
if not self._config.has_option(section, option):
return
return self._config.get(section, option)
[docs] def remove(self, section, option):
if self.has_section(section):
self._config.remove_option(section, option)
[docs] def remove_section(self, section):
self._config.remove_section(section)
[docs] def has_section(self, section):
return self._config.has_section(section)
[docs] def items(self, section):
if not self.has_section(section):
return []
return self._config.items(section)
#
# General routines
#
[docs]def register_config(config):
from kiwi.component import provide_utility
global _config
_config = config
try:
provide_utility(IStoqConfig, config, replace=True)
except NoConfigurationError:
msg = _(u"Error: Stoq configuration is not avaiable. Check that the "
"current user has a configuration file (~/.stoq/stoq.conf).")
if os.geteuid() == 0:
msg += _('\n\nYou are running stoq using sudo. That is not '
'recommended.')
raise SystemExit(msg)
[docs]def get_config():
return _config