24
23
from inventory import Inventory
25
24
from trace import mutter, note
26
25
from osutils import pumpfile, compare_files, filesize, quotefn, sha_file, \
27
joinpath, splitpath, appendpath, isdir, isfile, file_kind
26
joinpath, splitpath, appendpath, isdir, isfile, file_kind, fingerprint_file
28
27
from errors import bailout
30
29
from stat import S_ISREG, S_ISDIR, ST_MODE, ST_SIZE
74
73
doc="Inventory of this Tree")
76
75
def _check_retrieved(self, ie, f):
77
# TODO: Test this check by damaging the store?
76
fp = fingerprint_file(f)
78
79
if ie.text_size is not None:
80
if fs != ie.text_size:
80
if ie.text_size != fp['size']:
81
81
bailout("mismatched size for file %r in %r" % (ie.file_id, self._store),
82
82
["inventory expects %d bytes" % ie.text_size,
83
"file is actually %d bytes" % fs,
83
"file is actually %d bytes" % fp['size'],
84
84
"store is probably damaged/corrupt"])
88
if ie.text_sha1 != f_hash:
86
if ie.text_sha1 != fp['sha1']:
89
87
bailout("wrong SHA-1 for file %r in %r" % (ie.file_id, self._store),
90
88
["inventory expects %s" % ie.text_sha1,
91
"file is actually %s" % f_hash,
89
"file is actually %s" % fp['sha1'],
92
90
"store is probably damaged/corrupt"])
138
136
return "<%s of %s>" % (self.__class__.__name__,
141
def _rel(self, filename):
139
def abspath(self, filename):
142
140
return os.path.join(self.basedir, filename)
144
142
def has_filename(self, filename):
145
return os.path.exists(self._rel(filename))
143
return os.path.exists(self.abspath(filename))
147
145
def get_file(self, file_id):
148
146
return self.get_file_byname(self.id2path(file_id))
150
148
def get_file_byname(self, filename):
151
return file(self._rel(filename), 'rb')
149
return file(self.abspath(filename), 'rb')
153
151
def _get_store_filename(self, file_id):
154
return self._rel(self.id2path(file_id))
152
return self.abspath(self.id2path(file_id))
156
154
def has_id(self, file_id):
157
155
# files that have been deleted are excluded
158
156
if not self.inventory.has_id(file_id):
160
return os.access(self._rel(self.inventory.id2path(file_id)), os.F_OK)
158
return os.access(self.abspath(self.inventory.id2path(file_id)), os.F_OK)
162
160
def get_file_size(self, file_id):
163
161
return os.stat(self._get_store_filename(file_id))[ST_SIZE]
179
177
def file_kind(self, filename):
180
if isfile(self._rel(filename)):
178
if isfile(self.abspath(filename)):
182
elif isdir(self._rel(filename)):
180
elif isdir(self.abspath(filename)):
183
181
return 'directory'
265
263
def get_ignore_list(self):
266
"""Return list of ignore patterns."""
264
"""Return list of ignore patterns.
266
Cached in the Tree object after the first call.
268
if hasattr(self, '_ignorelist'):
269
return self._ignorelist
271
l = bzrlib.DEFAULT_IGNORE[:]
267
272
if self.has_filename(bzrlib.IGNORE_FILENAME):
268
273
f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
269
return [line.rstrip("\n\r") for line in f.readlines()]
271
return bzrlib.DEFAULT_IGNORE
274
l.extend([line.rstrip("\n\r") for line in f.readlines()])
274
279
def is_ignored(self, filename):
277
282
Patterns containing '/' need to match the whole path; others
278
283
match against only the last component."""
279
## TODO: Take them from a file, not hardcoded
280
284
## TODO: Use extended zsh-style globs maybe?
281
285
## TODO: Use '**' to match directories?
282
286
for pat in self.get_ignore_list():
310
314
ie = self._inventory[file_id]
311
315
f = self._store[ie.text_id]
312
316
mutter(" get fileid{%s} from %r" % (file_id, self))
314
if ie.text_size is None:
315
note("warning: no text size recorded on %r" % ie)
316
317
self._check_retrieved(ie, f)