~statik/ubuntu/karmic/ubuntuone-client/spbranch-experiment

« back to all changes in this revision

Viewing changes to canonical/ubuntuone/storage/syncdaemon/file_shelf.py

  • Committer: Rodney Dawes
  • Date: 2009-05-12 13:36:05 UTC
  • Revision ID: rodney.dawes@canonical.com-20090512133605-6aqs6e8xnnmp5u1p
        Import the code
        Hook up lint/trial tests in setup.py
        Use icontool now instead of including the render script
        Add missing python-gnome2-desktop to package dependencies
        Update debian/rules to fix the icon cache issue

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# canonical.ubuntuone.storagefs.diskcache - disk-backed filesystem cache
 
2
#
 
3
# Authors: Facundo Batista <facundo@canonical.com>
 
4
#          Guillermo Gonzalez  <guillermo.gonzalez@canonical.com>
 
5
#
 
6
# Copyright 2009 Canonical Ltd.
 
7
#
 
8
# This program is free software: you can redistribute it and/or modify it
 
9
# under the terms of the GNU General Public License version 3, as published
 
10
# by the Free Software Foundation.
 
11
#
 
12
# This program is distributed in the hope that it will be useful, but
 
13
# WITHOUT ANY WARRANTY; without even the implied warranties of
 
14
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
15
# PURPOSE.  See the GNU General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public License along
 
18
# with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
"""storage shelf using a files tree."""
 
20
 
 
21
from __future__ import with_statement
 
22
from UserDict import DictMixin
 
23
import cPickle
 
24
import os
 
25
 
 
26
class FileShelf(object, DictMixin):
 
27
    """ File based shelf.
 
28
 
 
29
    It support arbritary python objects as values (anything accepted by
 
30
    cPickle).  And support any valid file name as key.
 
31
    """
 
32
 
 
33
    def __init__(self, path, depth=3):
 
34
        """ Create a FileShelf.
 
35
 
 
36
        @param path: the path to use as the root of the shelf
 
37
        @param depth: the directory depth to use, can't be < 0. default is 3
 
38
        """
 
39
        self._path = path
 
40
        if depth < 0:
 
41
            raise ValueError("depth must be >= 0")
 
42
        self._depth = depth
 
43
        self._check_and_create_dirs(self._path)
 
44
 
 
45
    def _check_and_create_dirs(self, path):
 
46
        """ check if the path isn't a file and in case it don't exists,
 
47
        creates it
 
48
        """
 
49
        if os.path.exists(path) and os.path.isfile(path):
 
50
            os.unlink(path)
 
51
        if not os.path.exists(path):
 
52
            os.makedirs(path)
 
53
 
 
54
    def key_file(self, key):
 
55
        """ get the real key used by the storage from a key """
 
56
        # cannot use None to create files in the disk
 
57
        if key is None:
 
58
            raise ValueError("Invalid key: %r" % key)
 
59
 
 
60
        # length always needs to be longer (we have a uuid after all)
 
61
        if len(key) < self._depth:
 
62
            raise ValueError("The key (%r) needs to be longer!" % key)
 
63
 
 
64
        letters = [key[i] for i in xrange(0, self._depth)]
 
65
        path = os.path.join(self._path, *letters)
 
66
        self._check_and_create_dirs(path)
 
67
        return os.path.join(path, key)
 
68
 
 
69
    def has_key(self, key):
 
70
        """ True if the the shelf has the key """
 
71
        return os.path.exists(self.key_file(key))
 
72
 
 
73
    def keys(self):
 
74
        """ returns a iterator over the keys """
 
75
        for dirpath, dirnames, filenames in os.walk(self._path):
 
76
            for filename in filenames:
 
77
                yield filename
 
78
 
 
79
    def pop(self, key):
 
80
        """ returns the key and deletes the entry """
 
81
        k = self[key]
 
82
        del self[key]
 
83
        return k
 
84
 
 
85
    def __contains__(self, key):
 
86
        """ returns if the file storage has that key """
 
87
        # this method surely has some effect! pylint: disable-msg=W0104
 
88
        try:
 
89
            self[key]
 
90
        except KeyError:
 
91
            return False
 
92
        else:
 
93
            return True
 
94
 
 
95
    def __getitem__(self, key):
 
96
        """ getitem backed by the file storage """
 
97
        try:
 
98
            with open(self.key_file(key), "rb") as fd:
 
99
                data = cPickle.load(fd)
 
100
        except (IOError, OSError, EOFError):
 
101
            raise KeyError
 
102
        else:
 
103
            return data
 
104
 
 
105
    def __setitem__(self, key, value):
 
106
        """ setitem backed by the file storage """
 
107
        with open(self.key_file(key), "wb") as fh:
 
108
            cPickle.dump(value, fh, protocol=2)
 
109
            fh.flush()
 
110
            os.fsync(fh.fileno())
 
111
 
 
112
    def __delitem__(self, key):
 
113
        """ delitem backed by the file storage """
 
114
        os.remove(self.key_file(key))
 
115
 
 
116
    def __len__(self):
 
117
        """ The len of the shelf.
 
118
        To get len(keys) we need to iterate over the full key set.
 
119
        """
 
120
        counter = 0
 
121
        for key in self.keys():
 
122
            counter += 1
 
123
        return counter
 
124