251
251
ERROR_DIRECTORY = 267
254
if not getattr(struct, '_compile', None):
255
# Cannot pre-compile the dirstate pack_stat
256
def pack_stat(st, _encode=binascii.b2a_base64, _pack=struct.pack):
257
"""Convert stat values into a packed representation."""
258
return _encode(_pack('>LLLLLL', st.st_size & 0xFFFFFFFF,
259
int(st.st_mtime) & 0xFFFFFFFF, int(st.st_ctime) & 0xFFFFFFFF,
260
st.st_dev & 0xFFFFFFFF, st.st_ino & 0xFFFFFFFF,
263
# compile the struct compiler we need, so as to only do it once
264
from _struct import Struct
265
_compiled_pack = Struct('>LLLLLL').pack
266
def pack_stat(st, _encode=binascii.b2a_base64, _pack=_compiled_pack):
267
"""Convert stat values into a packed representation."""
268
# jam 20060614 it isn't really worth removing more entries if we
269
# are going to leave it in packed form.
270
# With only st_mtime and st_mode filesize is 5.5M and read time is 275ms
271
# With all entries, filesize is 5.9M and read time is maybe 280ms
272
# well within the noise margin
274
# base64 encoding always adds a final newline, so strip it off
275
# The current version
276
return _encode(_pack(st.st_size, int(st.st_mtime), int(st.st_ctime),
277
st.st_dev, st.st_ino & 0xFFFFFFFF, st.st_mode))[:-1]
278
# This is 0.060s / 1.520s faster by not encoding as much information
279
# return _encode(_pack('>LL', int(st.st_mtime), st.st_mode))[:-1]
280
# This is not strictly faster than _encode(_pack())[:-1]
281
# return '%X.%X.%X.%X.%X.%X' % (
282
# st.st_size, int(st.st_mtime), int(st.st_ctime),
283
# st.st_dev, st.st_ino, st.st_mode)
284
# Similar to the _encode(_pack('>LL'))
285
# return '%X.%X' % (int(st.st_mtime), st.st_mode)
288
def _unpack_stat(packed_stat):
289
"""Turn a packed_stat back into the stat fields.
291
This is meant as a debugging tool, should not be used in real code.
293
(st_size, st_mtime, st_ctime, st_dev, st_ino,
294
st_mode) = struct.unpack('>LLLLLL', binascii.a2b_base64(packed_stat))
295
return dict(st_size=st_size, st_mtime=st_mtime, st_ctime=st_ctime,
296
st_dev=st_dev, st_ino=st_ino, st_mode=st_mode)
254
299
class SHA1Provider(object):
255
300
"""An interface for getting sha1s of a file."""
1562
1607
source_path = child_basename
1563
1608
if new_path_utf8:
1565
new_path_utf8 + source_path[len(old_path_utf8):]
1609
target_path = new_path_utf8 + source_path[len(old_path):]
1567
if old_path_utf8 == '':
1568
1612
raise AssertionError("cannot rename directory to"
1570
target_path = source_path[len(old_path_utf8) + 1:]
1614
target_path = source_path[len(old_path) + 1:]
1571
1615
adds.append((None, target_path, entry[0][2], entry[1][1], False))
1572
1616
deletes.append(
1573
1617
(source_path, target_path, entry[0][2], None, False))
1575
(old_path_utf8, new_path_utf8, file_id, None, False))
1618
deletes.append((old_path_utf8, new_path, file_id, None, False))
1577
1619
self._check_delta_ids_absent(new_ids, delta, 1)
1579
1621
# Finish expunging deletes/first half of renames.
1648
1690
entry_key = st(dirname, basename, file_id)
1649
1691
block_index, present = self._find_block_index_from_key(entry_key)
1650
1692
if not present:
1651
# The block where we want to put the file is not present.
1652
# However, it might have just been an empty directory. Look for
1653
# the parent in the basis-so-far before throwing an error.
1654
parent_dir, parent_base = osutils.split(dirname)
1655
parent_block_idx, parent_entry_idx, _, parent_present = \
1656
self._get_block_entry_index(parent_dir, parent_base, 1)
1657
if not parent_present:
1658
self._raise_invalid(new_path, file_id,
1659
"Unable to find block for this record."
1660
" Was the parent added?")
1661
self._ensure_block(parent_block_idx, parent_entry_idx, dirname)
1693
self._raise_invalid(new_path, file_id,
1694
"Unable to find block for this record."
1695
" Was the parent added?")
1663
1696
block = self._dirblocks[block_index][1]
1664
1697
entry_index, present = self._find_entry_index(entry_key, block)
1864
1897
file_id, "This parent is not a directory.")
1866
1899
def _observed_sha1(self, entry, sha1, stat_value,
1867
_stat_to_minikind=_stat_to_minikind):
1900
_stat_to_minikind=_stat_to_minikind, _pack_stat=pack_stat):
1868
1901
"""Note the sha1 of a file.
1870
1903
:param entry: The entry the sha1 is for.
1876
1909
except KeyError:
1877
1910
# Unhandled kind
1912
packed_stat = _pack_stat(stat_value)
1879
1913
if minikind == 'f':
1880
1914
if self._cutoff_time is None:
1881
1915
self._sha_cutoff_time()
1882
1916
if (stat_value.st_mtime < self._cutoff_time
1883
1917
and stat_value.st_ctime < self._cutoff_time):
1884
1918
entry[1][0] = ('f', sha1, stat_value.st_size, entry[1][0][3],
1885
pack_stat(stat_value))
1886
1920
self._mark_modified([entry])
1888
1922
def _sha_cutoff_time(self):
1933
1967
# paths are produced by UnicodeDirReader on purpose.
1934
1968
abspath = abspath.encode(fs_encoding)
1935
1969
target = os.readlink(abspath)
1936
if fs_encoding not in ('utf-8', 'ascii'):
1970
if fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1937
1971
# Change encoding if needed
1938
1972
target = target.decode(fs_encoding).encode('UTF-8')
2441
2475
raise errors.BzrError('missing num_entries line')
2442
2476
self._num_entries = int(num_entries_line[len('num_entries: '):-1])
2444
def sha1_from_stat(self, path, stat_result):
2478
def sha1_from_stat(self, path, stat_result, _pack_stat=pack_stat):
2445
2479
"""Find a sha1 given a stat lookup."""
2446
return self._get_packed_stat_index().get(pack_stat(stat_result), None)
2480
return self._get_packed_stat_index().get(_pack_stat(stat_result), None)
2448
2482
def _get_packed_stat_index(self):
2449
2483
"""Get a packed_stat index of self._dirblocks."""
2575
2609
self.update_minimal(('', '', new_id), 'd',
2576
2610
path_utf8='', packed_stat=entry[1][0][4])
2577
2611
self._mark_modified()
2612
# XXX: This was added by Ian, we need to make sure there
2613
# are tests for it, because it isn't in bzr.dev TRUNK
2614
# It looks like the only place it is called is in setting the root
2615
# id of the tree. So probably we never had an _id_index when we
2616
# don't even have a root yet.
2617
if self._id_index is not None:
2618
self._add_to_id_index(self._id_index, entry[0])
2579
2620
def set_parent_trees(self, trees, ghosts):
2580
2621
"""Set the parent trees for the dirstate.
3287
3328
if self._id_index is not None:
3288
3329
for file_id, entry_keys in self._id_index.iteritems():
3289
3330
for entry_key in entry_keys:
3290
# Check that the entry in the map is pointing to the same
3292
3331
if entry_key[2] != file_id:
3293
3332
raise AssertionError(
3294
3333
'file_id %r did not match entry key %s'
3295
3334
% (file_id, entry_key))
3296
# And that from this entry key, we can look up the original
3298
block_index, present = self._find_block_index_from_key(entry_key)
3300
raise AssertionError('missing block for entry key: %r', entry_key)
3301
entry_index, present = self._find_entry_index(entry_key, self._dirblocks[block_index][1])
3303
raise AssertionError('missing entry for key: %r', entry_key)
3304
3335
if len(entry_keys) != len(set(entry_keys)):
3305
3336
raise AssertionError(
3306
3337
'id_index contained non-unique data for %s'