Catch ValueError exceptions.
[platform/upstream/gobject-introspection.git] / giscanner / cachestore.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
19 #
20
21 import cPickle
22 import hashlib
23 import os
24 import errno
25
26
27 def _get_cachedir():
28     cachedir = os.path.join(os.environ['HOME'], '.cache')
29     if not os.path.exists(cachedir):
30         os.mkdir(cachedir, 0755)
31
32     scannerdir = os.path.join(cachedir, 'g-ir-scanner')
33     if not os.path.exists(scannerdir):
34         os.mkdir(scannerdir, 0755)
35     # If it exists and is a file, don't cache at all
36     elif not os.path.isdir(scannerdir):
37         return None
38     return scannerdir
39
40
41 class CacheStore(object):
42
43     def __init__(self):
44         try:
45             self._directory = _get_cachedir()
46         except OSError, e:
47             if e.errno != errno.EPERM:
48                 raise
49             self._directory = None
50
51     def _get_filename(self, filename):
52         # If we couldn't create the directory we're probably
53         # on a read only home directory where we just disable
54         # the cache all together.
55         if self._directory is None:
56             return
57         hexdigest = hashlib.sha1(filename).hexdigest()
58         return os.path.join(self._directory, hexdigest)
59
60     def _cache_is_valid(self, store_filename, filename):
61         return (os.stat(store_filename).st_mtime >=
62                 os.stat(filename).st_mtime)
63
64     def _purge_cache(self, filename):
65         try:
66             os.unlink(filename)
67         except IOError, e:
68             # Permission denied
69             if e.errno == errno.EACCES:
70                 return
71             # File does not exist
72             elif e.errno == errno.ENOENT:
73                 return
74             else:
75                 raise
76
77     def store(self, filename, data):
78         store_filename = self._get_filename(filename)
79         if store_filename is None:
80             return
81         if (os.path.exists(store_filename) and
82             self._cache_is_valid(store_filename, filename)):
83             return None
84         fd = open(store_filename, 'w')
85         try:
86             cPickle.dump(data, fd)
87         except IOError, e:
88             # No space left on device
89             if e.errno == e.ENOSPC:
90                 return
91             else:
92                 raise
93
94     def load(self, filename):
95         store_filename = self._get_filename(filename)
96         if store_filename is None:
97             return
98         try:
99             fd = open(store_filename)
100         except IOError, e:
101             if e.errno == errno.ENOENT:
102                 return None
103             else:
104                 raise
105         if not self._cache_is_valid(store_filename, filename):
106             return None
107         try:
108             data = cPickle.load(fd)
109         except (EOFError, ValueError, cPickle.BadPickleGet):
110             # Broken cache entry, remove it
111             self._purge_cache(store_filename)
112             data = None
113         return data