summaryrefslogtreecommitdiff
path: root/src/leap/common/config/baseconfig.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/common/config/baseconfig.py')
-rw-r--r--src/leap/common/config/baseconfig.py207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py
new file mode 100644
index 0000000..699d734
--- /dev/null
+++ b/src/leap/common/config/baseconfig.py
@@ -0,0 +1,207 @@
+# -*- coding: utf-8 -*-
+# baseconfig.py
+# Copyright (C) 2013 LEAP
+#
+# 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 3 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Implements the abstract base class for configuration
+"""
+
+import copy
+import logging
+import functools
+import os
+
+from abc import ABCMeta, abstractmethod
+
+from leap.common.check import leap_assert
+from leap.common.files import mkdir_p
+from leap.common.config.pluggableconfig import PluggableConfig
+from leap.common.config.prefixers import get_platform_prefixer
+
+logger = logging.getLogger(__name__)
+
+
+class BaseConfig:
+ """
+ Abstract base class for any JSON based configuration.
+ """
+
+ __metaclass__ = ABCMeta
+
+ """
+ Standalone is a class wide parameter.
+
+ :param standalone: if True it will return the prefix for a
+ standalone application. Otherwise, it will
+ return the system
+ default for configuration storage.
+ :type standalone: bool
+ """
+ standalone = False
+
+ def __init__(self):
+ self._data = {}
+ self._config_checker = None
+
+ @abstractmethod
+ def _get_spec(self):
+ """
+ Returns the spec object for the specific configuration.
+ """
+ return None
+
+ def _safe_get_value(self, key):
+ """
+ Tries to return a value only if the config has already been loaded.
+
+ :rtype: depends on the config structure, dict, str, array, int
+ :return: returns the value for the specified key in the config
+ """
+ leap_assert(self._config_checker, "Load the config first")
+ return self._config_checker.config.get(key, None)
+
+ def get_path_prefix(self):
+ """
+ Returns the platform dependant path prefixer
+ """
+ return get_platform_prefixer().get_path_prefix(
+ standalone=self.standalone)
+
+ def loaded(self):
+ """
+ Returns True if the configuration has been already
+ loaded. False otherwise
+ """
+ return self._config_checker is not None
+
+ def save(self, path_list):
+ """
+ Saves the current configuration to disk.
+
+ :param path_list: list of components that form the relative
+ path to configuration. The absolute path
+ will be calculated depending on the platform.
+ :type path_list: list
+
+ :return: True if saved to disk correctly, False otherwise
+ """
+ config_path = os.path.join(self.get_path_prefix(), *(path_list[:-1]))
+ mkdir_p(config_path)
+
+ try:
+ self._config_checker.serialize(os.path.join(config_path,
+ path_list[-1]))
+ except Exception as e:
+ logger.warning("%s" % (e,))
+ raise
+ return True
+
+ def load(self, path="", data=None, mtime=None, relative=True):
+ """
+ Loads the configuration from disk.
+
+ :param path: if relative=True, this is a relative path
+ to configuration. The absolute path
+ will be calculated depending on the platform
+ :type path: str
+
+ :param relative: if True, path is relative. If False, it's absolute.
+ :type relative: bool
+
+ :return: True if loaded from disk correctly, False otherwise
+ :rtype: bool
+ """
+
+ if relative is True:
+ config_path = os.path.join(
+ self.get_path_prefix(), path)
+ else:
+ config_path = path
+
+ self._config_checker = PluggableConfig(format="json")
+ self._config_checker.options = copy.deepcopy(self._get_spec())
+
+ try:
+ if data is None:
+ self._config_checker.load(fromfile=config_path, mtime=mtime)
+ else:
+ self._config_checker.load(data, mtime=mtime)
+ except Exception as e:
+ logger.error("Something went wrong while loading " +
+ "the config from %s\n%s" % (config_path, e))
+ self._config_checker = None
+ return False
+ return True
+
+
+class LocalizedKey(object):
+ """
+ Decorator used for keys that are localized in a configuration.
+ """
+
+ def __init__(self, func, **kwargs):
+ self._func = func
+
+ def __call__(self, instance, lang=None):
+ """
+ Tries to return the string for the specified language, otherwise
+ returns the default language string.
+
+ :param lang: language code
+ :type lang: str
+
+ :return: localized value from the possible values returned by
+ self._func
+ It returns None in case that the provider does not provides
+ a matching pair of default_language and string for
+ that language.
+ e.g.:
+ 'default_language': 'es',
+ 'description': {'en': 'test description'}
+ Note that the json schema can't check that.
+ """
+ descriptions = self._func(instance)
+ config_lang = instance.get_default_language()
+ if lang is None:
+ lang = config_lang
+
+ for key in descriptions.keys():
+ if lang.startswith(key):
+ config_lang = key
+ break
+
+ description_lang = descriptions.get(config_lang)
+ if description_lang is None:
+ logger.error("There is a misconfiguration in the "
+ "provider's language strings.")
+
+ return description_lang
+
+ def __get__(self, instance, instancetype):
+ """
+ Implement the descriptor protocol to make decorating instance
+ method possible.
+ """
+ # Return a partial function with the first argument is the instance
+ # of the class decorated.
+ return functools.partial(self.__call__, instance)
+
+if __name__ == "__main__":
+ try:
+ config = BaseConfig() # should throw TypeError for _get_spec
+ except Exception as e:
+ assert isinstance(e, TypeError), "Something went wrong"
+ print "Abstract BaseConfig class is working as expected"