~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/dirstate.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-20 12:19:29 UTC
  • mfrom: (6437.23.11 2.5)
  • mto: (6581.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6582.
  • Revision ID: jelmer@samba.org-20120220121929-7ni2psvjoatm1yp4
Merge bzr/2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
218
218
 
219
219
"""
220
220
 
 
221
from __future__ import absolute_import
 
222
 
221
223
import bisect
222
 
import binascii
223
224
import errno
224
225
import operator
225
226
import os
226
227
from stat import S_IEXEC
227
228
import stat
228
 
import struct
229
229
import sys
230
230
import time
231
231
import zlib
251
251
ERROR_DIRECTORY = 267
252
252
 
253
253
 
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, int(st.st_mtime),
259
 
            int(st.st_ctime), st.st_dev, st.st_ino & 0xFFFFFFFF,
260
 
            st.st_mode))[:-1]
261
 
else:
262
 
    # compile the struct compiler we need, so as to only do it once
263
 
    from _struct import Struct
264
 
    _compiled_pack = Struct('>LLLLLL').pack
265
 
    def pack_stat(st, _encode=binascii.b2a_base64, _pack=_compiled_pack):
266
 
        """Convert stat values into a packed representation."""
267
 
        # jam 20060614 it isn't really worth removing more entries if we
268
 
        # are going to leave it in packed form.
269
 
        # With only st_mtime and st_mode filesize is 5.5M and read time is 275ms
270
 
        # With all entries, filesize is 5.9M and read time is maybe 280ms
271
 
        # well within the noise margin
272
 
 
273
 
        # base64 encoding always adds a final newline, so strip it off
274
 
        # The current version
275
 
        return _encode(_pack(st.st_size, int(st.st_mtime), int(st.st_ctime),
276
 
            st.st_dev, st.st_ino & 0xFFFFFFFF, st.st_mode))[:-1]
277
 
        # This is 0.060s / 1.520s faster by not encoding as much information
278
 
        # return _encode(_pack('>LL', int(st.st_mtime), st.st_mode))[:-1]
279
 
        # This is not strictly faster than _encode(_pack())[:-1]
280
 
        # return '%X.%X.%X.%X.%X.%X' % (
281
 
        #      st.st_size, int(st.st_mtime), int(st.st_ctime),
282
 
        #      st.st_dev, st.st_ino, st.st_mode)
283
 
        # Similar to the _encode(_pack('>LL'))
284
 
        # return '%X.%X' % (int(st.st_mtime), st.st_mode)
285
 
 
286
 
 
287
 
def _unpack_stat(packed_stat):
288
 
    """Turn a packed_stat back into the stat fields.
289
 
 
290
 
    This is meant as a debugging tool, should not be used in real code.
291
 
    """
292
 
    (st_size, st_mtime, st_ctime, st_dev, st_ino,
293
 
     st_mode) = struct.unpack('>LLLLLL', binascii.a2b_base64(packed_stat))
294
 
    return dict(st_size=st_size, st_mtime=st_mtime, st_ctime=st_ctime,
295
 
                st_dev=st_dev, st_ino=st_ino, st_mode=st_mode)
296
 
 
297
 
 
298
254
class SHA1Provider(object):
299
255
    """An interface for getting sha1s of a file."""
300
256
 
1605
1561
                    else:
1606
1562
                        source_path = child_basename
1607
1563
                    if new_path_utf8:
1608
 
                        target_path = new_path_utf8 + source_path[len(old_path):]
 
1564
                        target_path = \
 
1565
                            new_path_utf8 + source_path[len(old_path_utf8):]
1609
1566
                    else:
1610
 
                        if old_path == '':
 
1567
                        if old_path_utf8 == '':
1611
1568
                            raise AssertionError("cannot rename directory to"
1612
1569
                                                 " itself")
1613
 
                        target_path = source_path[len(old_path) + 1:]
 
1570
                        target_path = source_path[len(old_path_utf8) + 1:]
1614
1571
                    adds.append((None, target_path, entry[0][2], entry[1][1], False))
1615
1572
                    deletes.append(
1616
1573
                        (source_path, target_path, entry[0][2], None, False))
1617
 
                deletes.append((old_path_utf8, new_path, file_id, None, False))
 
1574
                deletes.append(
 
1575
                    (old_path_utf8, new_path_utf8, file_id, None, False))
 
1576
 
1618
1577
        self._check_delta_ids_absent(new_ids, delta, 1)
1619
1578
        try:
1620
1579
            # Finish expunging deletes/first half of renames.
1896
1855
                    file_id, "This parent is not a directory.")
1897
1856
 
1898
1857
    def _observed_sha1(self, entry, sha1, stat_value,
1899
 
        _stat_to_minikind=_stat_to_minikind, _pack_stat=pack_stat):
 
1858
        _stat_to_minikind=_stat_to_minikind):
1900
1859
        """Note the sha1 of a file.
1901
1860
 
1902
1861
        :param entry: The entry the sha1 is for.
1908
1867
        except KeyError:
1909
1868
            # Unhandled kind
1910
1869
            return None
1911
 
        packed_stat = _pack_stat(stat_value)
1912
1870
        if minikind == 'f':
1913
1871
            if self._cutoff_time is None:
1914
1872
                self._sha_cutoff_time()
1915
1873
            if (stat_value.st_mtime < self._cutoff_time
1916
1874
                and stat_value.st_ctime < self._cutoff_time):
1917
1875
                entry[1][0] = ('f', sha1, stat_value.st_size, entry[1][0][3],
1918
 
                               packed_stat)
 
1876
                               pack_stat(stat_value))
1919
1877
                self._mark_modified([entry])
1920
1878
 
1921
1879
    def _sha_cutoff_time(self):
1966
1924
            # paths are produced by UnicodeDirReader on purpose.
1967
1925
            abspath = abspath.encode(fs_encoding)
1968
1926
        target = os.readlink(abspath)
1969
 
        if fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
 
1927
        if fs_encoding not in ('utf-8', 'ascii'):
1970
1928
            # Change encoding if needed
1971
1929
            target = target.decode(fs_encoding).encode('UTF-8')
1972
1930
        return target
2474
2432
            raise errors.BzrError('missing num_entries line')
2475
2433
        self._num_entries = int(num_entries_line[len('num_entries: '):-1])
2476
2434
 
2477
 
    def sha1_from_stat(self, path, stat_result, _pack_stat=pack_stat):
 
2435
    def sha1_from_stat(self, path, stat_result):
2478
2436
        """Find a sha1 given a stat lookup."""
2479
 
        return self._get_packed_stat_index().get(_pack_stat(stat_result), None)
 
2437
        return self._get_packed_stat_index().get(pack_stat(stat_result), None)
2480
2438
 
2481
2439
    def _get_packed_stat_index(self):
2482
2440
        """Get a packed_stat index of self._dirblocks."""
3397
3355
 
3398
3356
 
3399
3357
def py_update_entry(state, entry, abspath, stat_value,
3400
 
                 _stat_to_minikind=DirState._stat_to_minikind,
3401
 
                 _pack_stat=pack_stat):
 
3358
                 _stat_to_minikind=DirState._stat_to_minikind):
3402
3359
    """Update the entry based on what is actually on disk.
3403
3360
 
3404
3361
    This function only calculates the sha if it needs to - if the entry is
3417
3374
    except KeyError:
3418
3375
        # Unhandled kind
3419
3376
        return None
3420
 
    packed_stat = _pack_stat(stat_value)
 
3377
    packed_stat = pack_stat(stat_value)
3421
3378
    (saved_minikind, saved_link_or_sha1, saved_file_size,
3422
3379
     saved_executable, saved_packed_stat) = entry[1][0]
3423
3380
 
4296
4253
        _bisect_path_left,
4297
4254
        _bisect_path_right,
4298
4255
        cmp_by_dirs,
 
4256
        pack_stat,
4299
4257
        ProcessEntryC as _process_entry,
4300
4258
        update_entry as update_entry,
4301
4259
        )
4307
4265
        _bisect_path_left,
4308
4266
        _bisect_path_right,
4309
4267
        cmp_by_dirs,
 
4268
        pack_stat,
4310
4269
        )
4311
4270
    # FIXME: It would be nice to be able to track moved lines so that the
4312
4271
    # corresponding python code can be moved to the _dirstate_helpers_py