add persistent option for db
authorEmmanuel Garette <egarette@cadoles.com>
Tue, 20 Aug 2013 20:45:11 +0000 (22:45 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Tue, 20 Aug 2013 20:45:11 +0000 (22:45 +0200)
21 files changed:
tiramisu/config.py
tiramisu/plugins/__init__.py [deleted file]
tiramisu/plugins/dictionary/__init__.py [deleted file]
tiramisu/plugins/dictionary/cache.py [deleted file]
tiramisu/plugins/dictionary/setting.py [deleted file]
tiramisu/plugins/dictionary/value.py [deleted file]
tiramisu/plugins/sqlite3/__init__.py [deleted file]
tiramisu/plugins/sqlite3/cache.py [deleted file]
tiramisu/plugins/sqlite3/setting.py [deleted file]
tiramisu/plugins/sqlite3/value.py [deleted file]
tiramisu/setting.py
tiramisu/storage/__init__.py [new file with mode: 0644]
tiramisu/storage/dictionary/__init__.py [new file with mode: 0644]
tiramisu/storage/dictionary/setting.py [new file with mode: 0644]
tiramisu/storage/dictionary/storage.py [new file with mode: 0644]
tiramisu/storage/dictionary/value.py [new file with mode: 0644]
tiramisu/storage/sqlite3/__init__.py [new file with mode: 0644]
tiramisu/storage/sqlite3/setting.py [new file with mode: 0644]
tiramisu/storage/sqlite3/storage.py [new file with mode: 0644]
tiramisu/storage/sqlite3/value.py [new file with mode: 0644]
tiramisu/value.py

index f60497f..e7372d8 100644 (file)
@@ -24,11 +24,15 @@ from time import time
 from tiramisu.error import PropertiesOptionError, ConfigError
 from tiramisu.option import OptionDescription, Option, SymLinkOption, \
     BaseInformation
-from tiramisu.setting import groups, Settings, default_encoding, default_storage
+from tiramisu.setting import groups, Settings, default_encoding, storage_type
 from tiramisu.value import Values
 from tiramisu.i18n import _
 
 
+def gen_id(config):
+    return str(id(config)) + str(time())
+
+
 class SubConfig(BaseInformation):
     "sub configuration management entry"
     __slots__ = ('_impl_context', '_impl_descr')
@@ -473,6 +477,13 @@ class CommonConfig(SubConfig):
     "abstract base class for the Config and the MetaConfig"
     __slots__ = ('_impl_values', '_impl_settings', '_impl_meta')
 
+    def _init_storage(self, config_id, is_persistent):
+        if config_id is None:
+            config_id = gen_id(self)
+        import_lib = 'tiramisu.storage.{0}.storage'.format(storage_type)
+        return __import__(import_lib, globals(), locals(), ['Storage'],
+                              -1).Storage(config_id, is_persistent)
+
     def _impl_build_all_paths(self):
         self.cfgimpl_get_description().impl_build_cache()
 
@@ -517,7 +528,7 @@ class Config(CommonConfig):
     "main configuration management entry"
     __slots__ = tuple()
 
-    def __init__(self, descr):
+    def __init__(self, descr, config_id=None, is_persistent=False):
         """ Configuration option management master class
 
         :param descr: describes the configuration schema
@@ -525,9 +536,9 @@ class Config(CommonConfig):
         :param context: the current root config
         :type context: `Config`
         """
-        config_id = str(id(self)) + str(time())
-        self._impl_settings = Settings(self, config_id, default_storage)
-        self._impl_values = Values(self, config_id, default_storage)
+        storage = self._init_storage(config_id, is_persistent)
+        self._impl_settings = Settings(self, storage)
+        self._impl_values = Values(self, storage)
         super(Config, self).__init__(descr, self)
         self._impl_build_all_paths()
         self._impl_meta = None
@@ -545,7 +556,7 @@ class Config(CommonConfig):
 class MetaConfig(CommonConfig):
     __slots__ = ('_impl_children',)
 
-    def __init__(self, children, meta=True):
+    def __init__(self, children, meta=True, config_id=None, is_persistent=False):
         if not isinstance(children, list):
             raise ValueError(_("metaconfig's children must be a list"))
         self._impl_descr = None
@@ -564,10 +575,12 @@ class MetaConfig(CommonConfig):
                     raise ValueError(_("child has already a metaconfig's"))
                 child._impl_meta = self
 
-        config_id = str(id(self))
+        if config_id is None:
+            config_id = gen_id(self)
         self._impl_children = children
-        self._impl_settings = Settings(self, config_id, default_storage)
-        self._impl_values = Values(self, config_id, default_storage)
+        storage = self._init_storage(config_id, is_persistent)
+        self._impl_settings = Settings(self, storage)
+        self._impl_values = Values(self, storage)
         self._impl_meta = None
         self._impl_informations = {}
 
diff --git a/tiramisu/plugins/__init__.py b/tiramisu/plugins/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tiramisu/plugins/dictionary/__init__.py b/tiramisu/plugins/dictionary/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tiramisu/plugins/dictionary/cache.py b/tiramisu/plugins/dictionary/cache.py
deleted file mode 100644 (file)
index d84964d..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- coding: utf-8 -*-
-"default plugin for cache: set it in a simple dictionary"
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
-#
-# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-# ____________________________________________________________
-
-
-class Cache(object):
-    __slots__ = ('_cache',)
-    key_is_path = False
-
-    def __init__(self):
-        self._cache = {}
-
-    def setcache(self, cache_type, opt, val, time):
-        self._cache[opt] = (val, time)
-
-    def getcache(self, cache_type, opt, exp):
-        value, created = self._cache[opt]
-        if exp < created:
-            return True, value
-        return False, None
-
-    def hascache(self, cache_type, opt):
-        return opt in self._cache
-
-    def reset_expired_cache(self, cache_type, exp):
-        keys = self._cache.keys()
-        for key in keys:
-            val, created = self._cache[key]
-            if exp > created:
-                del(self._cache[key])
-
-    def reset_all_cache(self, cache_type):
-        self._cache.clear()
-
-    def get_cached(self, cache_type, context):
-        """return all values in a dictionary
-        example: {option1: ('value1', 'time1'), option2: ('value2', 'time2')}
-        """
-        return self._cache
diff --git a/tiramisu/plugins/dictionary/setting.py b/tiramisu/plugins/dictionary/setting.py
deleted file mode 100644 (file)
index 5b7b67d..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-# -*- coding: utf-8 -*-
-"default plugin for setting: set it in a simple dictionary"
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
-#
-# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-# ____________________________________________________________
-from tiramisu.plugins.dictionary.cache import Cache
-
-
-class Settings(Cache):
-    __slots__ = ('_properties', '_permissives')
-
-    def __init__(self, config_id):
-        # properties attribute: the name of a property enables this property
-        # key is None for global properties
-        self._properties = {}
-        # permissive properties
-        self._permissives = {}
-        super(Settings, self).__init__()
-
-    # propertives
-    def setproperties(self, opt, properties):
-        self._properties[opt] = properties
-
-    def getproperties(self, opt, default_properties):
-        return self._properties.get(opt, set(default_properties))
-
-    def hasproperties(self, opt):
-        return opt in self._properties
-
-    def reset_all_propertives(self):
-        self._properties.clear()
-
-    def reset_properties(self, opt):
-        try:
-            del(self._properties[opt])
-        except KeyError:
-            pass
-
-    def get_properties(self, context):
-        return self._properties
-
-    # permissive
-    def setpermissive(self, opt, permissive):
-        self._permissives[opt] = frozenset(permissive)
-
-    def getpermissive(self, opt=None):
-        return self._permissives.get(opt, frozenset())
diff --git a/tiramisu/plugins/dictionary/value.py b/tiramisu/plugins/dictionary/value.py
deleted file mode 100644 (file)
index 501c318..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-"default plugin for value: set it in a simple dictionary"
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
-#
-# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-# ____________________________________________________________
-
-#FIXME
-from tiramisu.plugins.dictionary.cache import Cache
-
-
-class Values(Cache):
-    __slots__ = ('_values',)
-
-    def __init__(self, config_id):
-        """init plugin means create values storage
-        """
-        self._values = {}
-        # should init cache too
-        super(Values, self).__init__()
-
-    # value
-    def setvalue(self, opt, value, owner):
-        """set value for an option
-        a specified value must be associated to an owner
-        """
-        self._values[opt] = (owner, value)
-
-    def getvalue(self, opt):
-        """get value for an option
-        return: only value, not the owner
-        """
-        return self._values[opt][1]
-
-    def hasvalue(self, opt):
-        """if opt has a value
-        return: boolean
-        """
-        return opt in self._values
-
-    def resetvalue(self, opt):
-        """remove value means delete value in storage
-        """
-        del(self._values[opt])
-
-    def get_modified_values(self):
-        """return all values in a dictionary
-        example: {option1: (owner, 'value1'), option2: (owner, 'value2')}
-        """
-        return self._values
-
-    # owner
-    def setowner(self, opt, owner):
-        """change owner for an option
-        """
-        self._values[opt] = (owner, self._values[opt][1])
-
-    def getowner(self, opt, default):
-        """get owner for an option
-        return: owner object
-        """
-        return self._values.get(opt, (default, None))[0]
diff --git a/tiramisu/plugins/sqlite3/__init__.py b/tiramisu/plugins/sqlite3/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tiramisu/plugins/sqlite3/cache.py b/tiramisu/plugins/sqlite3/cache.py
deleted file mode 100644 (file)
index 8d47e35..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-# -*- coding: utf-8 -*-
-"default plugin for cache: set it in a simple dictionary"
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
-#
-# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-# ____________________________________________________________
-
-from pickle import dumps, loads
-import sqlite3
-
-
-class Cache(object):
-    __slots__ = ('_conn', '_cursor')
-    key_is_path = True
-
-    def __init__(self, config_id, cache_type):
-        cache_table = 'CREATE TABLE IF NOT EXISTS cache_{0}(path text primary key, value text, time real)'.format(cache_type)
-        self._conn = sqlite3.connect(config_id + '.db')
-        self._conn.text_factory = str
-        self._cursor = self._conn.cursor()
-        self._cursor.execute(cache_table)
-
-    # value
-    def _sqlite_decode(self, value):
-        return loads(value)
-
-    def _sqlite_encode(self, value):
-        if isinstance(value, list):
-            value = list(value)
-        return dumps(value)
-
-    def setcache(self, cache_type, path, val, time):
-        convert_value = self._sqlite_encode(val)
-        self._cursor.execute("DELETE FROM cache_{0} WHERE path = ?".format(cache_type), (path,))
-        self._cursor.execute("INSERT INTO cache_{0}(path, value, time) VALUES (?, ?, ?)".format(cache_type),
-                             (path, convert_value, time))
-        self._conn.commit()
-
-    def getcache(self, cache_type, path, exp):
-        self._cursor.execute("SELECT value FROM cache_{0} WHERE path = ? AND time >= ?".format(cache_type), (path, exp))
-        cached = self._cursor.fetchone()
-        if cached is None:
-            return False, None
-        else:
-            return True, self._sqlite_decode(cached[0])
-
-    def hascache(self, cache_type, path):
-        self._cursor.execute("SELECT value FROM cache_{0} WHERE path = ?".format(cache_type), (path,))
-        return self._cursor.fetchone() is not None
-
-    def reset_expired_cache(self, cache_type, exp):
-        self._cursor.execute("DELETE FROM cache_{0} WHERE time < ?".format(cache_type), (exp,))
-        self._conn.commit()
-
-    def reset_all_cache(self, cache_type):
-        self._cursor.execute("DELETE FROM cache_{0}".format(cache_type))
-        self._conn.commit()
-
-    def get_cached(self, cache_type, context):
-        """return all values in a dictionary
-        example: {option1: ('value1', 'time1'), option2: ('value2', 'time2')}
-        """
-        self._cursor.execute("SELECT * FROM cache_{0}".format(cache_type))
-        ret = {}
-        for path, value, time in self._cursor.fetchall():
-            opt = context.cfgimpl_get_description().impl_get_opt_by_path(path)
-            value = self._sqlite_decode(value)
-            ret[opt] = (value, time)
-        return ret
diff --git a/tiramisu/plugins/sqlite3/setting.py b/tiramisu/plugins/sqlite3/setting.py
deleted file mode 100644 (file)
index bee0550..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-# -*- coding: utf-8 -*-
-"default plugin for setting: set it in a simple dictionary"
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
-#
-# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-# ____________________________________________________________
-from tiramisu.plugins.sqlite3.cache import Cache
-
-
-class Settings(Cache):
-    __slots__ = tuple()
-
-    def __init__(self, config_id):
-        settings_table = 'CREATE TABLE IF NOT EXISTS property(path text primary key, properties text)'
-        permissives_table = 'CREATE TABLE IF NOT EXISTS permissive(path text primary key, permissives text)'
-        # should init cache too
-        super(Settings, self).__init__(config_id, 'property')
-        self._cursor.execute(settings_table)
-        self._cursor.execute(permissives_table)
-        self._conn.commit()
-
-    # propertives
-    def setproperties(self, path, properties):
-        self._cursor.execute("DELETE FROM property WHERE path = ?", (path,))
-        self._cursor.execute("INSERT INTO property(path, properties) VALUES (?, ?)",
-                             (path, self._sqlite_encode(properties)))
-        self._conn.commit()
-
-    def getproperties(self, path, default_properties):
-        self._cursor.execute("SELECT properties FROM property WHERE path = ?", (path,))
-        value = self._cursor.fetchone()
-        if value is None:
-            return set(default_properties)
-        else:
-            return set(self._sqlite_decode(value[0]))
-
-    def hasproperties(self, path):
-        return self._cursor.execute("SELECT properties FROM property WHERE path = ?", (path,)) is not None
-
-    def reset_all_propertives(self):
-        self._cursor.execute("DELETE FROM property")
-        self._conn.commit()
-
-    def reset_properties(self, path):
-        self._cursor.execute("DELETE FROM property WHERE path = ?", (path,))
-        self._conn.commit()
-
-    def get_properties(self, context):
-        """return all properties in a dictionary
-        """
-        self._cursor.execute("SELECT * FROM property")
-        ret = {}
-        for path, properties in self._cursor.fetchall():
-            if path == '_none':
-                opt = None
-            else:
-                opt = context.cfgimpl_get_description().impl_get_opt_by_path(path)
-            properties = self._sqlite_decode(properties)
-            ret[opt] = properties
-        return ret
-
-    # permissive
-    def setpermissive(self, path, permissive):
-        self._cursor.execute("DELETE FROM permissive WHERE path = ?", (path,))
-        self._cursor.execute("INSERT INTO permissive(path, permissives) VALUES (?, ?)",
-                             (path, self._sqlite_encode(permissive)))
-        self._conn.commit()
-
-    def getpermissive(self, path='_none'):
-        self._cursor.execute("SELECT permissives FROM permissive WHERE path = ?", (path,))
-        permissives = self._cursor.fetchone()
-        if permissives is None:
-            return frozenset()
-        else:
-            return frozenset(self._sqlite_decode(permissives[0]))
diff --git a/tiramisu/plugins/sqlite3/value.py b/tiramisu/plugins/sqlite3/value.py
deleted file mode 100644 (file)
index 85fb640..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-# -*- coding: utf-8 -*-
-"default plugin for value: set it in a simple dictionary"
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
-#
-# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-# ____________________________________________________________
-
-from tiramisu.plugins.sqlite3.cache import Cache
-from tiramisu.setting import owners
-
-
-class Values(Cache):
-    __slots__ = tuple()
-
-    def __init__(self, config_id):
-        """init plugin means create values storage
-        """
-        values_table = 'CREATE TABLE IF NOT EXISTS value(path text primary key, value text, owner text)'
-        # should init cache too
-        super(Values, self).__init__(config_id, 'value')
-        self._cursor.execute(values_table)
-        self._conn.commit()
-
-    # sqlite
-    def _sqlite_select(self, path):
-        self._cursor.execute("SELECT value FROM value WHERE path = ?", (path,))
-        return self._cursor.fetchone()
-
-    # value
-    def setvalue(self, path, value, owner):
-        """set value for an option
-        a specified value must be associated to an owner
-        """
-        self.resetvalue(path)
-        self._cursor.execute("INSERT INTO value(path, value, owner) VALUES (?, ?, ?)",
-                             (path, self._sqlite_encode(value), str(owner)))
-        self._conn.commit()
-
-    def getvalue(self, path):
-        """get value for an option
-        return: only value, not the owner
-        """
-        return self._sqlite_decode(self._sqlite_select(path)[0])
-
-    def hasvalue(self, path):
-        """if opt has a value
-        return: boolean
-        """
-        return self._sqlite_select(path) is not None
-
-    def resetvalue(self, path):
-        """remove value means delete value in storage
-        """
-        self._cursor.execute("DELETE FROM value WHERE path = ?", (path,))
-        self._conn.commit()
-
-    def get_modified_values(self, context):
-        """return all values in a dictionary
-        example: {option1: (owner, 'value1'), option2: (owner, 'value2')}
-        """
-        self._cursor.execute("SELECT value")
-        ret = {}
-        for path, value, owner in self._cursor.fetchall():
-            opt = context.cfgimpl_get_description().impl_get_opt_by_path(path)
-            owner = getattr(owners, owner)
-
-            value = self._sqlite_decode(value)
-            ret[opt] = (owner, value)
-        return ret
-
-    # owner
-    def setowner(self, path, owner):
-        """change owner for an option
-        """
-        self._cursor.execute("UPDATE value SET owner = ? WHERE path = ?", (str(owner), path))
-        self._conn.commit()
-
-    def getowner(self, path, default):
-        """get owner for an option
-        return: owner object
-        """
-        self._cursor.execute("SELECT owner FROM value WHERE path = ?", (path,))
-        owner = self._cursor.fetchone()
-        if owner is None:
-            return default
-        else:
-            return getattr(owners, owner[0])
-
-    def __del__(self):
-        self._cursor.close()
-        self._conn.close()
index 95149c8..b4cdc7a 100644 (file)
@@ -34,7 +34,7 @@ ro_append = ('frozen', 'disabled', 'validator', 'everything_frozen',
 rw_remove = ('permissive', 'everything_frozen', 'mandatory')
 rw_append = ('frozen', 'disabled', 'validator', 'hidden')
 default_properties = ('expire', 'validator')
-default_storage = 'dictionary'
+storage_type = 'dictionary'
 
 
 class _const:
@@ -183,13 +183,13 @@ class Settings(object):
     "``Config()``'s configuration options"
     __slots__ = ('context', '_owner', '_p_')
 
-    def __init__(self, context, config_id, plugin_name):
+    def __init__(self, context, storage):
         # generic owner
         self._owner = owners.user
         self.context = context
-        import_lib = 'tiramisu.plugins.{0}.setting'.format(plugin_name)
+        import_lib = 'tiramisu.storage.{0}.setting'.format(storage_type)
         self._p_ = __import__(import_lib, globals(), locals(), ['Settings'],
-                              -1).Settings(config_id)
+                              -1).Settings(storage)
 
     def _getkey(self, opt):
         if self._p_.key_is_path:
diff --git a/tiramisu/storage/__init__.py b/tiramisu/storage/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tiramisu/storage/dictionary/__init__.py b/tiramisu/storage/dictionary/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tiramisu/storage/dictionary/setting.py b/tiramisu/storage/dictionary/setting.py
new file mode 100644 (file)
index 0000000..519c844
--- /dev/null
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+"default plugin for setting: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+from tiramisu.storage.dictionary.storage import Cache
+
+
+class Settings(Cache):
+    __slots__ = ('_properties', '_permissives')
+
+    def __init__(self, storage):
+        # properties attribute: the name of a property enables this property
+        # key is None for global properties
+        self._properties = {}
+        # permissive properties
+        self._permissives = {}
+        super(Settings, self).__init__()
+
+    # propertives
+    def setproperties(self, opt, properties):
+        self._properties[opt] = properties
+
+    def getproperties(self, opt, default_properties):
+        return self._properties.get(opt, set(default_properties))
+
+    def hasproperties(self, opt):
+        return opt in self._properties
+
+    def reset_all_propertives(self):
+        self._properties.clear()
+
+    def reset_properties(self, opt):
+        try:
+            del(self._properties[opt])
+        except KeyError:
+            pass
+
+    def get_properties(self, context):
+        return self._properties
+
+    # permissive
+    def setpermissive(self, opt, permissive):
+        self._permissives[opt] = frozenset(permissive)
+
+    def getpermissive(self, opt=None):
+        return self._permissives.get(opt, frozenset())
diff --git a/tiramisu/storage/dictionary/storage.py b/tiramisu/storage/dictionary/storage.py
new file mode 100644 (file)
index 0000000..2180adf
--- /dev/null
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+"default plugin for cache: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+
+
+from tiramisu.i18n import _
+
+
+class Storage(object):
+    __slots__ = tuple()
+    def __init__(self, config_id, is_persistent):
+        if is_persistent:
+            raise ValueError(_('a dictionary cannot be persistent'))
+
+
+class Cache(object):
+    __slots__ = ('_cache',)
+    key_is_path = False
+
+    def __init__(self):
+        self._cache = {}
+
+    def setcache(self, cache_type, opt, val, time):
+        self._cache[opt] = (val, time)
+
+    def getcache(self, cache_type, opt, exp):
+        value, created = self._cache[opt]
+        if exp < created:
+            return True, value
+        return False, None
+
+    def hascache(self, cache_type, opt):
+        return opt in self._cache
+
+    def reset_expired_cache(self, cache_type, exp):
+        keys = self._cache.keys()
+        for key in keys:
+            val, created = self._cache[key]
+            if exp > created:
+                del(self._cache[key])
+
+    def reset_all_cache(self, cache_type):
+        self._cache.clear()
+
+    def get_cached(self, cache_type, context):
+        """return all values in a dictionary
+        example: {option1: ('value1', 'time1'), option2: ('value2', 'time2')}
+        """
+        return self._cache
diff --git a/tiramisu/storage/dictionary/value.py b/tiramisu/storage/dictionary/value.py
new file mode 100644 (file)
index 0000000..0f80f73
--- /dev/null
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+"default plugin for value: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+
+from tiramisu.storage.dictionary.storage import Cache
+
+
+class Values(Cache):
+    __slots__ = ('_values',)
+
+    def __init__(self, storage):
+        """init plugin means create values storage
+        """
+        self._values = {}
+        # should init cache too
+        super(Values, self).__init__()
+
+    # value
+    def setvalue(self, opt, value, owner):
+        """set value for an option
+        a specified value must be associated to an owner
+        """
+        self._values[opt] = (owner, value)
+
+    def getvalue(self, opt):
+        """get value for an option
+        return: only value, not the owner
+        """
+        return self._values[opt][1]
+
+    def hasvalue(self, opt):
+        """if opt has a value
+        return: boolean
+        """
+        return opt in self._values
+
+    def resetvalue(self, opt):
+        """remove value means delete value in storage
+        """
+        del(self._values[opt])
+
+    def get_modified_values(self):
+        """return all values in a dictionary
+        example: {option1: (owner, 'value1'), option2: (owner, 'value2')}
+        """
+        return self._values
+
+    # owner
+    def setowner(self, opt, owner):
+        """change owner for an option
+        """
+        self._values[opt] = (owner, self._values[opt][1])
+
+    def getowner(self, opt, default):
+        """get owner for an option
+        return: owner object
+        """
+        return self._values.get(opt, (default, None))[0]
diff --git a/tiramisu/storage/sqlite3/__init__.py b/tiramisu/storage/sqlite3/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tiramisu/storage/sqlite3/setting.py b/tiramisu/storage/sqlite3/setting.py
new file mode 100644 (file)
index 0000000..5e722d3
--- /dev/null
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+"default plugin for setting: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+from tiramisu.storage.sqlite3.storage import Cache
+
+
+class Settings(Cache):
+    __slots__ = tuple()
+
+    def __init__(self, storage):
+        settings_table = 'CREATE TABLE IF NOT EXISTS property(path text primary key, properties text)'
+        permissives_table = 'CREATE TABLE IF NOT EXISTS permissive(path text primary key, permissives text)'
+        # should init cache too
+        super(Settings, self).__init__('property', storage)
+        self.storage.execute(settings_table, commit=False)
+        self.storage.execute(permissives_table)
+
+    # propertives
+    def setproperties(self, path, properties):
+        self.storage.execute("DELETE FROM property WHERE path = ?", (path,), False)
+        self.storage.execute("INSERT INTO property(path, properties) VALUES (?, ?)",
+                             (path, self._sqlite_encode(properties)))
+
+    def getproperties(self, path, default_properties):
+        value = self.storage.select("SELECT properties FROM property WHERE path = ?", (path,))
+        if value is None:
+            return set(default_properties)
+        else:
+            return set(self._sqlite_decode(value[0]))
+
+    def hasproperties(self, path):
+        return self.storage.select("SELECT properties FROM property WHERE path = ?", (path,)) is not None
+
+    def reset_all_propertives(self):
+        self.storage.execute("DELETE FROM property")
+
+    def reset_properties(self, path):
+        self.storage.execute("DELETE FROM property WHERE path = ?", (path,))
+
+    def get_properties(self, context):
+        """return all properties in a dictionary
+        """
+        ret = {}
+        for path, properties in self.storage.select("SELECT * FROM property", only_one=False):
+            if path == '_none':
+                opt = None
+            else:
+                opt = context.cfgimpl_get_description().impl_get_opt_by_path(path)
+            properties = self._sqlite_decode(properties)
+            ret[opt] = properties
+        return ret
+
+    # permissive
+    def setpermissive(self, path, permissive):
+        self.storage.execute("DELETE FROM permissive WHERE path = ?", (path,), False)
+        self.storage.execute("INSERT INTO permissive(path, permissives) VALUES (?, ?)",
+                             (path, self._sqlite_encode(permissive)))
+
+    def getpermissive(self, path='_none'):
+        permissives = self.storage.select("SELECT permissives FROM permissive WHERE path = ?", (path,))
+        if permissives is None:
+            return frozenset()
+        else:
+            return frozenset(self._sqlite_decode(permissives[0]))
diff --git a/tiramisu/storage/sqlite3/storage.py b/tiramisu/storage/sqlite3/storage.py
new file mode 100644 (file)
index 0000000..6ce03c4
--- /dev/null
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+"default plugin for cache: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+
+from pickle import dumps, loads
+from os import unlink
+import sqlite3
+
+
+class Storage(object):
+    __slots__ = ('_conn', '_cursor', 'is_persistent', 'db_file')
+
+    def __init__(self, config_id, is_persistent):
+        self.is_persistent = is_persistent
+        self.db_file = config_id + '.db'
+        self._conn = sqlite3.connect(self.db_file)
+        self._conn.text_factory = str
+        self._cursor = self._conn.cursor()
+
+    def execute(self, sql, params=None, commit=True):
+        if params is None:
+            params = tuple()
+        self._cursor.execute(sql, params)
+        if commit:
+            self._conn.commit()
+
+    def select(self, sql, params=None, only_one=True):
+        self.execute(sql, params=params, commit=False)
+        if only_one:
+            return self._cursor.fetchone()
+        else:
+            return self._cursor.fetchall()
+
+    def __del__(self):
+        self._cursor.close()
+        self._conn.close()
+        if not self.is_persistent:
+            unlink(self.db_file)
+
+
+class Cache(object):
+    __slots__ = ('storage',)
+    key_is_path = True
+
+    def __init__(self, cache_type, storage):
+        self.storage = storage
+        cache_table = 'CREATE TABLE IF NOT EXISTS cache_{0}(path '.format(
+            cache_type)
+        cache_table += 'text primary key, value text, time real)'
+        self.storage.execute(cache_table)
+
+    # value
+    def _sqlite_decode(self, value):
+        return loads(value)
+
+    def _sqlite_encode(self, value):
+        if isinstance(value, list):
+            value = list(value)
+        return dumps(value)
+
+    def setcache(self, cache_type, path, val, time):
+        convert_value = self._sqlite_encode(val)
+        self.storage.execute("DELETE FROM cache_{0} WHERE path = ?".format(
+            cache_type), (path,), False)
+        self.storage.execute("INSERT INTO cache_{0}(path, value, time) "
+                             "VALUES (?, ?, ?)".format(cache_type),
+                             (path, convert_value, time))
+
+    def getcache(self, cache_type, path, exp):
+        cached = self.storage.select("SELECT value FROM cache_{0} WHERE "
+                                     "path = ? AND time >= ?".format(
+                                         cache_type), (path, exp))
+        if cached is None:
+            return False, None
+        else:
+            return True, self._sqlite_decode(cached[0])
+
+    def hascache(self, cache_type, path):
+        return self.storage.select("SELECT value FROM cache_{0} WHERE "
+                                   "path = ?".format(cache_type),
+                                   (path,)) is not None
+
+    def reset_expired_cache(self, cache_type, exp):
+        self.storage.execute("DELETE FROM cache_{0} WHERE time < ?".format(
+            cache_type), (exp,))
+
+    def reset_all_cache(self, cache_type):
+        self.storage.execute("DELETE FROM cache_{0}".format(cache_type))
+
+    def get_cached(self, cache_type, context):
+        """return all values in a dictionary
+        example: {option1: ('value1', 'time1'), option2: ('value2', 'time2')}
+        """
+        ret = {}
+        for path, value, time in self.storage.select("SELECT * FROM cache_{0}"
+                                                     "".format(cache_type),
+                                                     only_one=False):
+            opt = context.cfgimpl_get_description().impl_get_opt_by_path(path)
+            value = self._sqlite_decode(value)
+            ret[opt] = (value, time)
+        return ret
diff --git a/tiramisu/storage/sqlite3/value.py b/tiramisu/storage/sqlite3/value.py
new file mode 100644 (file)
index 0000000..525c899
--- /dev/null
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+"default plugin for value: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+
+from tiramisu.storage.sqlite3.storage import Cache
+from tiramisu.setting import owners
+
+
+class Values(Cache):
+    __slots__ = tuple()
+
+    def __init__(self, storage):
+        """init plugin means create values storage
+        """
+        values_table = 'CREATE TABLE IF NOT EXISTS value(path text primary key, value text, owner text)'
+        # should init cache too
+        super(Values, self).__init__('value', storage)
+        self.storage.execute(values_table)
+
+    # sqlite
+    def _sqlite_select(self, path):
+        return self.storage.select("SELECT value FROM value WHERE path = ?", (path,))
+
+    # value
+    def setvalue(self, path, value, owner):
+        """set value for an option
+        a specified value must be associated to an owner
+        """
+        self.resetvalue(path)
+        self.storage.execute("INSERT INTO value(path, value, owner) VALUES (?, ?, ?)",
+                             (path, self._sqlite_encode(value), str(owner)))
+
+    def getvalue(self, path):
+        """get value for an option
+        return: only value, not the owner
+        """
+        return self._sqlite_decode(self._sqlite_select(path)[0])
+
+    def hasvalue(self, path):
+        """if opt has a value
+        return: boolean
+        """
+        return self._sqlite_select(path) is not None
+
+    def resetvalue(self, path):
+        """remove value means delete value in storage
+        """
+        self.storage.execute("DELETE FROM value WHERE path = ?", (path,))
+
+    def get_modified_values(self, context):
+        """return all values in a dictionary
+        example: {option1: (owner, 'value1'), option2: (owner, 'value2')}
+        """
+        ret = {}
+        for path, value, owner in self.storage.select("SELECT value", only_one=False):
+            opt = context.cfgimpl_get_description().impl_get_opt_by_path(path)
+            owner = getattr(owners, owner)
+
+            value = self._sqlite_decode(value)
+            ret[opt] = (owner, value)
+        return ret
+
+    # owner
+    def setowner(self, path, owner):
+        """change owner for an option
+        """
+        self.storage.execute("UPDATE value SET owner = ? WHERE path = ?", (str(owner), path))
+
+    def getowner(self, path, default):
+        """get owner for an option
+        return: owner object
+        """
+        owner = self.storage.select("SELECT owner FROM value WHERE path = ?", (path,))
+        if owner is None:
+            return default
+        else:
+            return getattr(owners, owner[0])
index 60b9255..988fd0b 100644 (file)
@@ -20,7 +20,7 @@
 from time import time
 from copy import copy
 from tiramisu.error import ConfigError, SlaveError
-from tiramisu.setting import owners, multitypes, expires_time
+from tiramisu.setting import owners, multitypes, expires_time, storage_type
 from tiramisu.autolib import carry_out_calculation
 from tiramisu.i18n import _
 from tiramisu.option import SymLinkOption
@@ -33,7 +33,7 @@ class Values(object):
     """
     __slots__ = ('context', '_p_')
 
-    def __init__(self, context, config_id, plugin_name):
+    def __init__(self, context, storage):
         """
         Initializes the values's dict.
 
@@ -42,9 +42,9 @@ class Values(object):
         """
 
         self.context = context
-        import_lib = 'tiramisu.plugins.{0}.value'.format(plugin_name)
+        import_lib = 'tiramisu.storage.{0}.value'.format(storage_type)
         self._p_ = __import__(import_lib, globals(), locals(), ['Values'],
-                              -1).Values(config_id)
+                              -1).Values(storage)
 
     def _getkey(self, opt):
         if self._p_.key_is_path: