23
22
__copyright__ = "Copyright (C) 2005 Canonical Ltd."
24
23
__author__ = "Martin Pool <mbp@canonical.com>"
26
import os, tempfile, types, osutils
25
import os, tempfile, types, osutils, gzip, errno
27
26
from stat import ST_SIZE
28
27
from StringIO import StringIO
29
28
from trace import mutter
32
30
######################################################################
81
79
def __repr__(self):
82
80
return "%s(%r)" % (self.__class__.__name__, self._basedir)
84
def add(self, f, fileid):
82
def add(self, f, fileid, compressed=True):
85
83
"""Add contents of a file into the store.
87
85
:param f: An open file, or file-like object."""
96
if fileid not in self:
97
filename = self._path(fileid)
98
f = file(filename, 'wb')
101
## os.fsync(f.fileno())
103
osutils.make_readonly(filename)
95
p = self._path(fileid)
96
if os.access(p, os.F_OK) or os.access(p + '.gz', os.F_OK):
97
bailout("store %r already contains id %r" % (self._basedir, fileid))
100
f = gzip.GzipFile(p + '.gz', 'wb')
101
os.chmod(p + '.gz', 0444)
106
110
def __contains__(self, fileid):
108
return os.access(self._path(fileid), os.R_OK)
112
p = self._path(fileid)
113
return (os.access(p, os.R_OK)
114
or os.access(p + '.gz', os.R_OK))
116
# TODO: Guard against the same thing being stored twice, compressed and uncompresse
111
118
def __iter__(self):
112
return iter(os.listdir(self._basedir))
119
for f in os.listdir(self._basedir):
121
# TODO: case-insensitive?
114
126
def __len__(self):
115
127
return len(os.listdir(self._basedir))
117
129
def __getitem__(self, fileid):
118
130
"""Returns a file reading from a particular entry."""
119
return file(self._path(fileid), 'rb')
131
p = self._path(fileid)
133
return gzip.GzipFile(p + '.gz', 'rb')
135
if e.errno == errno.ENOENT:
121
140
def total_size(self):
122
"""Return (count, bytes)"""
141
"""Return (count, bytes)
143
This is the (compressed) size stored on disk, not the size of
127
total += os.stat(self._path(fid))[ST_SIZE]
151
total += os.stat(p)[ST_SIZE]
153
total += os.stat(p + '.gz')[ST_SIZE]
128
155
return count, total
130
def delete_all(self):
134
def delete(self, fileid):
135
"""Remove nominated store entry.
137
Most stores will be add-only."""
138
filename = self._path(fileid)
139
## osutils.make_writable(filename)
143
"""Remove store; only allowed if it is empty."""
144
os.rmdir(self._basedir)
145
mutter("%r destroyed" % self)
156
167
ImmutableStore.__init__(self, tempfile.mkdtemp())
158
169
def __del__(self):
170
for f in os.listdir(self._basedir):
171
fpath = os.path.join(self._basedir, f)
172
# needed on windows, and maybe some other filesystems
173
os.chmod(fpath, 0600)
175
os.rmdir(self._basedir)
176
mutter("%r destroyed" % self)