/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/_dirstate_helpers_pyx.pyx

  • Committer: Robert Collins
  • Date: 2010-05-06 23:41:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506234135-yivbzczw1sejxnxc
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
expected to return an object which can be used to unlock them. This reduces
duplicate code when using cleanups. The previous 'tokens's returned by
``Branch.lock_write`` and ``Repository.lock_write`` are now attributes
on the result of the lock_write. ``repository.RepositoryWriteLockResult``
and ``branch.BranchWriteLockResult`` document this. (Robert Collins)

``log._get_info_for_log_files`` now takes an add_cleanup callable.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2010 Canonical Ltd
 
1
# Copyright (C) 2007, 2008, 2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
19
19
This is the python implementation for DirState functions.
20
20
"""
21
21
 
22
 
from __future__ import absolute_import
23
 
 
24
22
import binascii
25
23
import bisect
26
24
import errno
28
26
import stat
29
27
import sys
30
28
 
31
 
from .. import cache_utf8, errors, osutils
32
 
from .dirstate import DirState, DirstateCorrupt
33
 
from ..osutils import parent_directories, pathjoin, splitpath, is_inside_any, is_inside
34
 
from ..tree import TreeChange
 
29
from bzrlib import cache_utf8, errors, osutils
 
30
from bzrlib.dirstate import DirState
 
31
from bzrlib.osutils import parent_directories, pathjoin, splitpath
35
32
 
36
33
 
37
34
# This is the Windows equivalent of ENOTDIR
43
40
cdef int ERROR_DIRECTORY
44
41
ERROR_DIRECTORY = 267
45
42
 
 
43
#python2.4 support, and other platform-dependent includes
46
44
cdef extern from "python-compat.h":
47
45
    unsigned long htonl(unsigned long)
48
46
 
60
58
    ctypedef int intptr_t
61
59
 
62
60
 
 
61
 
63
62
cdef extern from "stdlib.h":
64
63
    unsigned long int strtoul(char *nptr, char **endptr, int base)
65
64
 
98
97
    object PyTuple_GetItem_void_object "PyTuple_GET_ITEM" (void* tpl, int index)
99
98
    object PyTuple_GET_ITEM(object tpl, Py_ssize_t index)
100
99
 
101
 
    unsigned long PyInt_AsUnsignedLongMask(object number) except? -1
102
100
 
103
 
    char *PyBytes_AsString(object p)
104
 
    char *PyBytes_AsString_obj "PyBytes_AsString" (PyObject *string)
105
 
    char *PyBytes_AS_STRING_void "PyBytes_AS_STRING" (void *p)
106
 
    int PyBytes_AsStringAndSize(object str, char **buffer, Py_ssize_t *length) except -1
107
 
    object PyBytes_FromString(char *)
108
 
    object PyBytes_FromStringAndSize(char *, Py_ssize_t)
109
 
    int PyBytes_Size(object p)
110
 
    int PyBytes_GET_SIZE_void "PyBytes_GET_SIZE" (void *p)
111
 
    int PyBytes_CheckExact(object p)
112
 
    int PyFloat_Check(object p)
113
 
    double PyFloat_AsDouble(object p)
114
 
    int PyLong_Check(object p)
 
101
    char *PyString_AsString(object p)
 
102
    char *PyString_AsString_obj "PyString_AsString" (PyObject *string)
 
103
    char *PyString_AS_STRING_void "PyString_AS_STRING" (void *p)
 
104
    int PyString_AsStringAndSize(object str, char **buffer, Py_ssize_t *length) except -1
 
105
    object PyString_FromString(char *)
 
106
    object PyString_FromStringAndSize(char *, Py_ssize_t)
 
107
    int PyString_Size(object p)
 
108
    int PyString_GET_SIZE_void "PyString_GET_SIZE" (void *p)
 
109
    int PyString_CheckExact(object p)
115
110
    void Py_INCREF(object o)
116
111
    void Py_DECREF(object o)
117
112
 
120
115
    int strncmp(char *s1, char *s2, int len)
121
116
    void *memchr(void *s, int c, size_t len)
122
117
    int memcmp(void *b1, void *b2, size_t len)
123
 
 
124
 
from ._str_helpers cimport (
125
 
    _my_memrchr,
126
 
    safe_string_from_size,
127
 
    )
128
 
 
129
 
from .._static_tuple_c cimport (
130
 
    import_static_tuple_c,
131
 
    StaticTuple,
132
 
    StaticTuple_New,
133
 
    StaticTuple_SET_ITEM
134
 
    )
135
 
 
136
 
import_static_tuple_c()
 
118
    # ??? memrchr is a GNU extension :(
 
119
    # void *memrchr(void *s, int c, size_t len)
 
120
 
 
121
 
 
122
cdef void* _my_memrchr(void *s, int c, size_t n): # cannot_raise
 
123
    # memrchr seems to be a GNU extension, so we have to implement it ourselves
 
124
    cdef char *pos
 
125
    cdef char *start
 
126
 
 
127
    start = <char*>s
 
128
    pos = start + n - 1
 
129
    while pos >= start:
 
130
        if pos[0] == c:
 
131
            return <void*>pos
 
132
        pos = pos - 1
 
133
    return NULL
137
134
 
138
135
 
139
136
def _py_memrchr(s, c):
148
145
    cdef int length
149
146
    cdef char *_c
150
147
 
151
 
    assert PyBytes_Size(c) == 1, 'Expected single character string not %r' % c
152
 
    _c = PyBytes_AsString(c)
153
 
    _s = PyBytes_AsString(s)
154
 
    length = PyBytes_Size(s)
 
148
    _s = PyString_AsString(s)
 
149
    length = PyString_Size(s)
155
150
 
 
151
    _c = PyString_AsString(c)
 
152
    assert PyString_Size(c) == 1,\
 
153
        'Must be a single character string, not %s' % (c,)
156
154
    found = _my_memrchr(_s, _c[0], length)
157
155
    if found == NULL:
158
156
        return None
159
157
    return <char*>found - <char*>_s
160
158
 
161
159
 
 
160
cdef object safe_string_from_size(char *s, Py_ssize_t size):
 
161
    if size < 0:
 
162
        raise AssertionError(
 
163
            'tried to create a string with an invalid size: %d'
 
164
            % (size))
 
165
    return PyString_FromStringAndSize(s, size)
 
166
 
 
167
 
162
168
cdef int _is_aligned(void *ptr): # cannot_raise
163
169
    """Is this pointer aligned to an integer size offset?
164
170
 
213
219
            cur2 = cur2 + 1
214
220
            continue
215
221
        # The current characters do not match
216
 
        if cur1[0] == b'/':
 
222
        if cur1[0] == c'/':
217
223
            return -1 # Reached the end of path1 segment first
218
 
        elif cur2[0] == b'/':
 
224
        elif cur2[0] == c'/':
219
225
            return 1 # Reached the end of path2 segment first
220
226
        elif cur1[0] < cur2[0]:
221
227
            return -1
231
237
    return 0
232
238
 
233
239
 
234
 
def lt_by_dirs(path1, path2):
 
240
def cmp_by_dirs(path1, path2):
235
241
    """Compare two paths directory by directory.
236
242
 
237
243
    This is equivalent to doing::
238
244
 
239
 
       operator.lt(path1.split('/'), path2.split('/'))
 
245
       cmp(path1.split('/'), path2.split('/'))
240
246
 
241
247
    The idea is that you should compare path components separately. This
242
 
    differs from plain ``path1 < path2`` for paths like ``'a-b'`` and ``a/b``.
243
 
    "a-b" comes after "a" but would come before "a/b" lexically.
 
248
    differs from plain ``cmp(path1, path2)`` for paths like ``'a-b'`` and
 
249
    ``a/b``. "a-b" comes after "a" but would come before "a/b" lexically.
244
250
 
245
251
    :param path1: first path
246
252
    :param path2: second path
247
 
    :return: True if path1 comes first, otherwise False
 
253
    :return: negative number if ``path1`` comes first,
 
254
        0 if paths are equal,
 
255
        and positive number if ``path2`` sorts first
248
256
    """
249
 
    if not PyBytes_CheckExact(path1):
250
 
        raise TypeError("'path1' must be a bytes string, not %s: %r"
 
257
    if not PyString_CheckExact(path1):
 
258
        raise TypeError("'path1' must be a plain string, not %s: %r"
251
259
                        % (type(path1), path1))
252
 
    if not PyBytes_CheckExact(path2):
253
 
        raise TypeError("'path2' must be a bytes string, not %s: %r"
 
260
    if not PyString_CheckExact(path2):
 
261
        raise TypeError("'path2' must be a plain string, not %s: %r"
254
262
                        % (type(path2), path2))
255
 
    return -1 == _cmp_by_dirs(PyBytes_AsString(path1),
256
 
                              PyBytes_Size(path1),
257
 
                              PyBytes_AsString(path2),
258
 
                              PyBytes_Size(path2))
259
 
 
260
 
 
261
 
def _lt_path_by_dirblock(path1, path2):
 
263
    return _cmp_by_dirs(PyString_AsString(path1),
 
264
                        PyString_Size(path1),
 
265
                        PyString_AsString(path2),
 
266
                        PyString_Size(path2))
 
267
 
 
268
 
 
269
def _cmp_path_by_dirblock(path1, path2):
262
270
    """Compare two paths based on what directory they are in.
263
271
 
264
272
    This generates a sort order, such that all children of a directory are
266
274
    children appear. But all grandchildren come after all children.
267
275
 
268
276
    In other words, all entries in a directory are sorted together, and
269
 
    directories are sorted in cmp_by_dirs order.
 
277
    directorys are sorted in cmp_by_dirs order.
270
278
 
271
279
    :param path1: first path
272
280
    :param path2: the second path
273
 
    :return: True if path1 comes first, otherwise False.
 
281
    :return: negative number if ``path1`` comes first,
 
282
        0 if paths are equal
 
283
        and a positive number if ``path2`` sorts first
274
284
    """
275
 
    if not PyBytes_CheckExact(path1):
 
285
    if not PyString_CheckExact(path1):
276
286
        raise TypeError("'path1' must be a plain string, not %s: %r"
277
287
                        % (type(path1), path1))
278
 
    if not PyBytes_CheckExact(path2):
 
288
    if not PyString_CheckExact(path2):
279
289
        raise TypeError("'path2' must be a plain string, not %s: %r"
280
290
                        % (type(path2), path2))
281
 
    # GZ 2017-06-09: This internal function really only needs lt as well.
282
 
    return (_cmp_path_by_dirblock_intern(PyBytes_AsString(path1),
283
 
                                         PyBytes_Size(path1),
284
 
                                         PyBytes_AsString(path2),
285
 
                                         PyBytes_Size(path2)) < 0)
 
291
    return _cmp_path_by_dirblock_intern(PyString_AsString(path1),
 
292
                                        PyString_Size(path1),
 
293
                                        PyString_AsString(path2),
 
294
                                        PyString_Size(path2))
286
295
 
287
296
 
288
297
cdef int _cmp_path_by_dirblock_intern(char *path1, int path1_len,
314
323
    if path2_len == 0:
315
324
        return 1
316
325
 
317
 
    basename1 = <char*>_my_memrchr(path1, b'/', path1_len)
 
326
    basename1 = <char*>_my_memrchr(path1, c'/', path1_len)
318
327
 
319
328
    if basename1 == NULL:
320
329
        basename1 = path1
321
330
        basename1_len = path1_len
322
 
        dirname1 = b''
 
331
        dirname1 = ''
323
332
        dirname1_len = 0
324
333
    else:
325
334
        dirname1 = path1
327
336
        basename1 = basename1 + 1
328
337
        basename1_len = path1_len - dirname1_len - 1
329
338
 
330
 
    basename2 = <char*>_my_memrchr(path2, b'/', path2_len)
 
339
    basename2 = <char*>_my_memrchr(path2, c'/', path2_len)
331
340
 
332
341
    if basename2 == NULL:
333
342
        basename2 = path2
334
343
        basename2_len = path2_len
335
 
        dirname2 = b''
 
344
        dirname2 = ''
336
345
        dirname2_len = 0
337
346
    else:
338
347
        dirname2 = path2
389
398
    if not PyList_CheckExact(paths):
390
399
        raise TypeError("you must pass a python list for 'paths' not: %s %r"
391
400
                        % (type(paths), paths))
392
 
    if not PyBytes_CheckExact(path):
 
401
    if not PyString_CheckExact(path):
393
402
        raise TypeError("you must pass a string for 'path' not: %s %r"
394
403
                        % (type(path), path))
395
404
 
396
405
    _hi = len(paths)
397
406
    _lo = 0
398
407
 
399
 
    path_cstr = PyBytes_AsString(path)
400
 
    path_size = PyBytes_Size(path)
 
408
    path_cstr = PyString_AsString(path)
 
409
    path_size = PyString_Size(path)
401
410
 
402
411
    while _lo < _hi:
403
 
        _mid = (_lo + _hi) // 2
 
412
        _mid = (_lo + _hi) / 2
404
413
        cur = PyList_GetItem_object_void(paths, _mid)
405
 
        cur_cstr = PyBytes_AS_STRING_void(cur)
406
 
        cur_size = PyBytes_GET_SIZE_void(cur)
 
414
        cur_cstr = PyString_AS_STRING_void(cur)
 
415
        cur_size = PyString_GET_SIZE_void(cur)
407
416
        if _cmp_path_by_dirblock_intern(cur_cstr, cur_size,
408
417
                                        path_cstr, path_size) < 0:
409
418
            _lo = _mid + 1
442
451
    if not PyList_CheckExact(paths):
443
452
        raise TypeError("you must pass a python list for 'paths' not: %s %r"
444
453
                        % (type(paths), paths))
445
 
    if not PyBytes_CheckExact(path):
 
454
    if not PyString_CheckExact(path):
446
455
        raise TypeError("you must pass a string for 'path' not: %s %r"
447
456
                        % (type(path), path))
448
457
 
449
458
    _hi = len(paths)
450
459
    _lo = 0
451
460
 
452
 
    path_cstr = PyBytes_AsString(path)
453
 
    path_size = PyBytes_Size(path)
 
461
    path_cstr = PyString_AsString(path)
 
462
    path_size = PyString_Size(path)
454
463
 
455
464
    while _lo < _hi:
456
 
        _mid = (_lo + _hi) // 2
 
465
        _mid = (_lo + _hi) / 2
457
466
        cur = PyList_GetItem_object_void(paths, _mid)
458
 
        cur_cstr = PyBytes_AS_STRING_void(cur)
459
 
        cur_size = PyBytes_GET_SIZE_void(cur)
 
467
        cur_cstr = PyString_AS_STRING_void(cur)
 
468
        cur_size = PyString_GET_SIZE_void(cur)
460
469
        if _cmp_path_by_dirblock_intern(path_cstr, path_size,
461
470
                                        cur_cstr, cur_size) < 0:
462
471
            _hi = _mid
487
496
    if not PyList_CheckExact(dirblocks):
488
497
        raise TypeError("you must pass a python list for 'dirblocks' not: %s %r"
489
498
                        % (type(dirblocks), dirblocks))
490
 
    if not PyBytes_CheckExact(dirname):
 
499
    if not PyString_CheckExact(dirname):
491
500
        raise TypeError("you must pass a string for dirname not: %s %r"
492
501
                        % (type(dirname), dirname))
493
502
    if hi is None:
496
505
        _hi = hi
497
506
 
498
507
    _lo = lo
499
 
    dirname_cstr = PyBytes_AsString(dirname)
500
 
    dirname_size = PyBytes_Size(dirname)
 
508
    dirname_cstr = PyString_AsString(dirname)
 
509
    dirname_size = PyString_Size(dirname)
501
510
 
502
511
    while _lo < _hi:
503
 
        _mid = (_lo + _hi) // 2
 
512
        _mid = (_lo + _hi) / 2
504
513
        # Grab the dirname for the current dirblock
505
514
        # cur = dirblocks[_mid][0]
506
515
        cur = PyTuple_GetItem_void_void(
507
516
                PyList_GetItem_object_void(dirblocks, _mid), 0)
508
 
        cur_cstr = PyBytes_AS_STRING_void(cur)
509
 
        cur_size = PyBytes_GET_SIZE_void(cur)
 
517
        cur_cstr = PyString_AS_STRING_void(cur)
 
518
        cur_size = PyString_GET_SIZE_void(cur)
510
519
        if _cmp_by_dirs(cur_cstr, cur_size, dirname_cstr, dirname_size) < 0:
511
520
            _lo = _mid + 1
512
521
        else:
529
538
    def __init__(self, text, state):
530
539
        self.state = state
531
540
        self.text = text
532
 
        self.text_cstr = PyBytes_AsString(text)
533
 
        self.text_size = PyBytes_Size(text)
 
541
        self.text_cstr = PyString_AsString(text)
 
542
        self.text_size = PyString_Size(text)
534
543
        self.end_cstr = self.text_cstr + self.text_size
535
544
        self.cur_cstr = self.text_cstr
536
545
 
545
554
            raise AssertionError('get_next() called when there are no chars'
546
555
                                 ' left')
547
556
        next = self.cur_cstr
548
 
        self.cur_cstr = <char*>memchr(next, b'\0', self.end_cstr - next)
 
557
        self.cur_cstr = <char*>memchr(next, c'\0', self.end_cstr - next)
549
558
        if self.cur_cstr == NULL:
550
559
            extra_len = self.end_cstr - next
551
 
            raise DirstateCorrupt(self.state,
 
560
            raise errors.DirstateCorrupt(self.state,
552
561
                'failed to find trailing NULL (\\0).'
553
562
                ' Trailing garbage: %r'
554
563
                % safe_string_from_size(next, extra_len))
575
584
        cdef int size
576
585
        # The first field should be an empty string left over from the Header
577
586
        first = self.get_next(&size)
578
 
        if first[0] != b'\0' and size == 0:
 
587
        if first[0] != c'\0' and size == 0:
579
588
            raise AssertionError('First character should be null not: %s'
580
589
                                 % (first,))
581
590
        return 0
591
600
        columns, then "current" columns, and then "parent" columns.
592
601
 
593
602
        :param num_trees: How many parent trees need to be parsed
594
 
        :param p_current_dirname: A pointer to the current PyBytes
 
603
        :param p_current_dirname: A pointer to the current PyString
595
604
            representing the directory name.
596
605
            We pass this in as a void * so that pyrex doesn't have to
597
606
            increment/decrement the PyObject reference counter for each
601
610
        :param new_block: This is to let the caller know that it needs to
602
611
            create a new directory block to store the next entry.
603
612
        """
604
 
        cdef StaticTuple path_name_file_id_key
605
 
        cdef StaticTuple tmp
 
613
        cdef object path_name_file_id_key
606
614
        cdef char *entry_size_cstr
607
615
        cdef unsigned long int entry_size
608
616
        cdef char* executable_cstr
618
626
        # Read the 'key' information (dirname, name, file_id)
619
627
        dirname_cstr = self.get_next(&cur_size)
620
628
        # Check to see if we have started a new directory block.
621
 
        # If so, then we need to create a new dirname PyBytes, so that it can
 
629
        # If so, then we need to create a new dirname PyString, so that it can
622
630
        # be used in all of the tuples. This saves time and memory, by re-using
623
631
        # the same object repeatedly.
624
632
 
625
633
        # Do the cheap 'length of string' check first. If the string is a
626
634
        # different length, then we *have* to be a different directory.
627
 
        if (cur_size != PyBytes_GET_SIZE_void(p_current_dirname[0])
 
635
        if (cur_size != PyString_GET_SIZE_void(p_current_dirname[0])
628
636
            or strncmp(dirname_cstr,
629
637
                       # Extract the char* from our current dirname string.  We
630
 
                       # know it is a PyBytes, so we can use
631
 
                       # PyBytes_AS_STRING, we use the _void version because
 
638
                       # know it is a PyString, so we can use
 
639
                       # PyString_AS_STRING, we use the _void version because
632
640
                       # we are tricking Pyrex by using a void* rather than an
633
641
                       # <object>
634
 
                       PyBytes_AS_STRING_void(p_current_dirname[0]),
 
642
                       PyString_AS_STRING_void(p_current_dirname[0]),
635
643
                       cur_size+1) != 0):
636
644
            dirname = safe_string_from_size(dirname_cstr, cur_size)
637
645
            p_current_dirname[0] = <void*>dirname
642
650
        # Build up the key that will be used.
643
651
        # By using <object>(void *) Pyrex will automatically handle the
644
652
        # Py_INCREF that we need.
645
 
        cur_dirname = <object>p_current_dirname[0]
646
 
        # Use StaticTuple_New to pre-allocate, rather than creating a regular
647
 
        # tuple and passing it to the StaticTuple constructor.
648
 
        # path_name_file_id_key = StaticTuple(<object>p_current_dirname[0],
649
 
        #                          self.get_next_str(),
650
 
        #                          self.get_next_str(),
651
 
        #                         )
652
 
        tmp = StaticTuple_New(3)
653
 
        Py_INCREF(cur_dirname); StaticTuple_SET_ITEM(tmp, 0, cur_dirname)
654
 
        cur_basename = self.get_next_str()
655
 
        cur_file_id = self.get_next_str()
656
 
        Py_INCREF(cur_basename); StaticTuple_SET_ITEM(tmp, 1, cur_basename)
657
 
        Py_INCREF(cur_file_id); StaticTuple_SET_ITEM(tmp, 2, cur_file_id)
658
 
        path_name_file_id_key = tmp
 
653
        path_name_file_id_key = (<object>p_current_dirname[0],
 
654
                                 self.get_next_str(),
 
655
                                 self.get_next_str(),
 
656
                                )
659
657
 
660
658
        # Parse all of the per-tree information. current has the information in
661
659
        # the same location as parent trees. The only difference is that 'info'
677
675
            entry_size_cstr = self.get_next(&cur_size)
678
676
            entry_size = strtoul(entry_size_cstr, NULL, 10)
679
677
            executable_cstr = self.get_next(&cur_size)
680
 
            is_executable = (executable_cstr[0] == b'y')
 
678
            is_executable = (executable_cstr[0] == c'y')
681
679
            info = self.get_next_str()
682
 
            # TODO: If we want to use StaticTuple_New here we need to be pretty
683
 
            #       careful. We are relying on a bit of Pyrex
684
 
            #       automatic-conversion from 'int' to PyInt, and that doesn't
685
 
            #       play well with the StaticTuple_SET_ITEM macro.
686
 
            #       Timing doesn't (yet) show a worthwile improvement in speed
687
 
            #       versus complexity and maintainability.
688
 
            # tmp = StaticTuple_New(5)
689
 
            # Py_INCREF(minikind); StaticTuple_SET_ITEM(tmp, 0, minikind)
690
 
            # Py_INCREF(fingerprint); StaticTuple_SET_ITEM(tmp, 1, fingerprint)
691
 
            # Py_INCREF(entry_size); StaticTuple_SET_ITEM(tmp, 2, entry_size)
692
 
            # Py_INCREF(is_executable); StaticTuple_SET_ITEM(tmp, 3, is_executable)
693
 
            # Py_INCREF(info); StaticTuple_SET_ITEM(tmp, 4, info)
694
 
            # PyList_Append(trees, tmp)
695
 
            PyList_Append(trees, StaticTuple(
 
680
            PyList_Append(trees, (
696
681
                minikind,     # minikind
697
682
                fingerprint,  # fingerprint
698
683
                entry_size,   # size
706
691
        # ensures that we always finish parsing a line on an end-of-entry
707
692
        # marker.
708
693
        trailing = self.get_next(&cur_size)
709
 
        if cur_size != 1 or not trailing.startswith(b'\n'):
710
 
            raise DirstateCorrupt(self.state,
 
694
        if cur_size != 1 or trailing[0] != c'\n':
 
695
            raise errors.DirstateCorrupt(self.state,
711
696
                'Bad parse, we expected to end on \\n, not: %d %s: %s'
712
697
                % (cur_size, safe_string_from_size(trailing, cur_size),
713
698
                   ret))
730
715
        self._init()
731
716
 
732
717
        current_block = []
733
 
        dirblocks = [(b'', current_block), (b'', [])]
 
718
        dirblocks = [('', current_block), ('', [])]
734
719
        self.state._dirblocks = dirblocks
735
 
        obj = b''
 
720
        obj = ''
736
721
        current_dirname = <void*>obj
737
722
        new_block = 0
738
723
        entry_count = 0
754
739
            PyList_Append(current_block, entry)
755
740
            entry_count = entry_count + 1
756
741
        if entry_count != expected_entry_count:
757
 
            raise DirstateCorrupt(self.state,
 
742
            raise errors.DirstateCorrupt(self.state,
758
743
                    'We read the wrong number of entries.'
759
744
                    ' We expected to read %s, but read %s'
760
745
                    % (expected_entry_count, entry_count))
797
782
_encode = binascii.b2a_base64
798
783
 
799
784
 
800
 
cdef unsigned long _time_to_unsigned(object t):  # cannot_raise
801
 
    if PyFloat_Check(t):
802
 
        t = t.__int__()
803
 
    return PyInt_AsUnsignedLongMask(t)
804
 
 
805
 
 
 
785
from struct import pack
806
786
cdef _pack_stat(stat_value):
807
787
    """return a string representing the stat value's key fields.
808
788
 
812
792
    cdef char result[6*4] # 6 long ints
813
793
    cdef int *aliased
814
794
    aliased = <int *>result
815
 
    aliased[0] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_size))
816
 
    # mtime and ctime will often be floats but get converted to PyInt within
817
 
    aliased[1] = htonl(_time_to_unsigned(stat_value.st_mtime))
818
 
    aliased[2] = htonl(_time_to_unsigned(stat_value.st_ctime))
819
 
    aliased[3] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_dev))
820
 
    aliased[4] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_ino))
821
 
    aliased[5] = htonl(PyInt_AsUnsignedLongMask(stat_value.st_mode))
822
 
    packed = PyBytes_FromStringAndSize(result, 6*4)
 
795
    aliased[0] = htonl(stat_value.st_size)
 
796
    aliased[1] = htonl(int(stat_value.st_mtime))
 
797
    aliased[2] = htonl(int(stat_value.st_ctime))
 
798
    aliased[3] = htonl(stat_value.st_dev)
 
799
    aliased[4] = htonl(stat_value.st_ino & 0xFFFFFFFF)
 
800
    aliased[5] = htonl(stat_value.st_mode)
 
801
    packed = PyString_FromStringAndSize(result, 6*4)
823
802
    return _encode(packed)[:-1]
824
803
 
825
804
 
826
 
def pack_stat(stat_value):
827
 
    """Convert stat value into a packed representation quickly with pyrex"""
828
 
    return _pack_stat(stat_value)
829
 
 
830
 
 
831
 
cpdef update_entry(self, entry, abspath, stat_value):
 
805
def update_entry(self, entry, abspath, stat_value):
 
806
    """Update the entry based on what is actually on disk.
 
807
 
 
808
    This function only calculates the sha if it needs to - if the entry is
 
809
    uncachable, or clearly different to the first parent's entry, no sha
 
810
    is calculated, and None is returned.
 
811
 
 
812
    :param entry: This is the dirblock entry for the file in question.
 
813
    :param abspath: The path on disk for this file.
 
814
    :param stat_value: (optional) if we already have done a stat on the
 
815
        file, re-use it.
 
816
    :return: None, or The sha1 hexdigest of the file (40 bytes) or link
 
817
        target of a symlink.
 
818
    """
 
819
    return _update_entry(self, entry, abspath, stat_value)
 
820
 
 
821
 
 
822
cdef _update_entry(self, entry, abspath, stat_value):
832
823
    """Update the entry based on what is actually on disk.
833
824
 
834
825
    This function only calculates the sha if it needs to - if the entry is
846
837
    # _st mode of the compiled stat objects.
847
838
    cdef int minikind, saved_minikind
848
839
    cdef void * details
849
 
    cdef int worth_saving
850
840
    minikind = minikind_from_mode(stat_value.st_mode)
851
841
    if 0 == minikind:
852
842
        return None
853
843
    packed_stat = _pack_stat(stat_value)
854
844
    details = PyList_GetItem_void_void(PyTuple_GetItem_void_void(<void *>entry, 1), 0)
855
 
    saved_minikind = PyBytes_AsString_obj(<PyObject *>PyTuple_GetItem_void_void(details, 0))[0]
856
 
    if minikind == b'd' and saved_minikind == b't':
857
 
        minikind = b't'
 
845
    saved_minikind = PyString_AsString_obj(<PyObject *>PyTuple_GetItem_void_void(details, 0))[0]
 
846
    if minikind == c'd' and saved_minikind == c't':
 
847
        minikind = c't'
858
848
    saved_link_or_sha1 = PyTuple_GetItem_void_object(details, 1)
859
849
    saved_file_size = PyTuple_GetItem_void_object(details, 2)
860
850
    saved_executable = PyTuple_GetItem_void_object(details, 3)
871
861
        and packed_stat == saved_packed_stat):
872
862
        # The stat hasn't changed since we saved, so we can re-use the
873
863
        # saved sha hash.
874
 
        if minikind == b'd':
 
864
        if minikind == c'd':
875
865
            return None
876
866
 
877
867
        # size should also be in packed_stat
881
871
    # If we have gotten this far, that means that we need to actually
882
872
    # process this entry.
883
873
    link_or_sha1 = None
884
 
    worth_saving = 1
885
 
    if minikind == b'f':
 
874
    if minikind == c'f':
886
875
        executable = self._is_executable(stat_value.st_mode,
887
876
                                         saved_executable)
888
877
        if self._cutoff_time is None:
890
879
        if (stat_value.st_mtime < self._cutoff_time
891
880
            and stat_value.st_ctime < self._cutoff_time
892
881
            and len(entry[1]) > 1
893
 
            and entry[1][1][0] != b'a'):
 
882
            and entry[1][1][0] != 'a'):
894
883
                # Could check for size changes for further optimised
895
884
                # avoidance of sha1's. However the most prominent case of
896
885
                # over-shaing is during initial add, which this catches.
897
886
            link_or_sha1 = self._sha1_file(abspath)
898
 
            entry[1][0] = (b'f', link_or_sha1, stat_value.st_size,
 
887
            entry[1][0] = ('f', link_or_sha1, stat_value.st_size,
899
888
                           executable, packed_stat)
900
889
        else:
901
 
            # This file is not worth caching the sha1. Either it is too new, or
902
 
            # it is newly added. Regardless, the only things we are changing
903
 
            # are derived from the stat, and so are not worth caching. So we do
904
 
            # *not* set the IN_MEMORY_MODIFIED flag. (But we'll save the
905
 
            # updated values if there is *other* data worth saving.)
906
 
            entry[1][0] = (b'f', b'', stat_value.st_size, executable,
907
 
                           DirState.NULLSTAT)
908
 
            worth_saving = 0
909
 
    elif minikind == b'd':
910
 
        entry[1][0] = (b'd', b'', 0, False, packed_stat)
911
 
        if saved_minikind != b'd':
 
890
            entry[1][0] = ('f', '', stat_value.st_size,
 
891
                           executable, DirState.NULLSTAT)
 
892
    elif minikind == c'd':
 
893
        link_or_sha1 = None
 
894
        entry[1][0] = ('d', '', 0, False, packed_stat)
 
895
        if saved_minikind != c'd':
912
896
            # This changed from something into a directory. Make sure we
913
897
            # have a directory block for it. This doesn't happen very
914
898
            # often, so this doesn't have to be super fast.
916
900
                self._get_block_entry_index(entry[0][0], entry[0][1], 0)
917
901
            self._ensure_block(block_index, entry_index,
918
902
                               pathjoin(entry[0][0], entry[0][1]))
919
 
        else:
920
 
            # Any changes are derived trivially from the stat object, not worth
921
 
            # re-writing a dirstate for just this
922
 
            worth_saving = 0
923
 
    elif minikind == b'l':
924
 
        if saved_minikind == b'l':
925
 
            # If the object hasn't changed kind, it isn't worth saving the
926
 
            # dirstate just for a symlink. The default is 'fast symlinks' which
927
 
            # save the target in the inode entry, rather than separately. So to
928
 
            # stat, we've already read everything off disk.
929
 
            worth_saving = 0
 
903
    elif minikind == c'l':
930
904
        link_or_sha1 = self._read_link(abspath, saved_link_or_sha1)
931
905
        if self._cutoff_time is None:
932
906
            self._sha_cutoff_time()
933
907
        if (stat_value.st_mtime < self._cutoff_time
934
908
            and stat_value.st_ctime < self._cutoff_time):
935
 
            entry[1][0] = (b'l', link_or_sha1, stat_value.st_size,
 
909
            entry[1][0] = ('l', link_or_sha1, stat_value.st_size,
936
910
                           False, packed_stat)
937
911
        else:
938
 
            entry[1][0] = (b'l', b'', stat_value.st_size,
 
912
            entry[1][0] = ('l', '', stat_value.st_size,
939
913
                           False, DirState.NULLSTAT)
940
 
    if worth_saving:
941
 
        # Note, even though _mark_modified will only set
942
 
        # IN_MEMORY_HASH_MODIFIED, it still isn't worth 
943
 
        self._mark_modified([entry])
 
914
    self._dirblock_state = DirState.IN_MEMORY_MODIFIED
944
915
    return link_or_sha1
945
916
 
946
917
 
947
918
# TODO: Do we want to worry about exceptions here?
948
919
cdef char _minikind_from_string(object string) except? -1:
949
920
    """Convert a python string to a char."""
950
 
    return PyBytes_AsString(string)[0]
 
921
    return PyString_AsString(string)[0]
951
922
 
952
923
 
953
924
cdef object _kind_absent
967
938
cdef object _minikind_to_kind(char minikind):
968
939
    """Create a string kind for minikind."""
969
940
    cdef char _minikind[1]
970
 
    if minikind == b'f':
 
941
    if minikind == c'f':
971
942
        return _kind_file
972
 
    elif minikind == b'd':
 
943
    elif minikind == c'd':
973
944
        return _kind_directory
974
 
    elif minikind == b'a':
 
945
    elif minikind == c'a':
975
946
        return _kind_absent
976
 
    elif minikind == b'r':
 
947
    elif minikind == c'r':
977
948
        return _kind_relocated
978
 
    elif minikind == b'l':
 
949
    elif minikind == c'l':
979
950
        return _kind_symlink
980
 
    elif minikind == b't':
 
951
    elif minikind == c't':
981
952
        return _kind_tree_reference
982
953
    _minikind[0] = minikind
983
 
    raise KeyError(PyBytes_FromStringAndSize(_minikind, 1))
 
954
    raise KeyError(PyString_FromStringAndSize(_minikind, 1))
984
955
 
985
956
 
986
957
cdef int _versioned_minikind(char minikind): # cannot_raise
987
958
    """Return non-zero if minikind is in fltd"""
988
 
    return (minikind == b'f' or
989
 
            minikind == b'd' or
990
 
            minikind == b'l' or
991
 
            minikind == b't')
 
959
    return (minikind == c'f' or
 
960
            minikind == c'd' or
 
961
            minikind == c'l' or
 
962
            minikind == c't')
992
963
 
993
964
 
994
965
cdef class ProcessEntryC:
1133
1104
            if self.target_index != 0:
1134
1105
                raise AssertionError("Unsupported target index %d" %
1135
1106
                                     self.target_index)
1136
 
            link_or_sha1 = update_entry(self.state, entry, path_info[4], path_info[3])
 
1107
            link_or_sha1 = _update_entry(self.state, entry, path_info[4], path_info[3])
1137
1108
            # The entry may have been modified by update_entry
1138
1109
            target_details = details_list[self.target_index]
1139
1110
            target_minikind = _minikind_from_string(target_details[0])
1142
1113
        # the rest of this function is 0.3 seconds on 50K paths, or
1143
1114
        # 0.000006 seconds per call.
1144
1115
        source_minikind = _minikind_from_string(source_details[0])
1145
 
        if ((_versioned_minikind(source_minikind) or source_minikind == b'r')
 
1116
        if ((_versioned_minikind(source_minikind) or source_minikind == c'r')
1146
1117
            and _versioned_minikind(target_minikind)):
1147
1118
            # claimed content in both: diff
1148
1119
            #   r    | fdlt   |      | add source to search, add id path move and perform
1149
1120
            #        |        |      | diff check on source-target
1150
1121
            #   r    | fdlt   |  a   | dangling file that was present in the basis.
1151
1122
            #        |        |      | ???
1152
 
            if source_minikind != b'r':
 
1123
            if source_minikind != c'r':
1153
1124
                old_dirname = entry[0][0]
1154
1125
                old_basename = entry[0][1]
1155
1126
                old_path = path = None
1157
1128
                # add the source to the search path to find any children it
1158
1129
                # has.  TODO ? : only add if it is a container ?
1159
1130
                if (not self.doing_consistency_expansion and 
1160
 
                    not is_inside_any(self.searched_specific_files,
 
1131
                    not osutils.is_inside_any(self.searched_specific_files,
1161
1132
                                             source_details[1])):
1162
1133
                    self.search_specific_files.add(source_details[1])
1163
1134
                    # expanding from a user requested path, parent expansion
1172
1143
                # update the source details variable to be the real
1173
1144
                # location.
1174
1145
                if old_entry == (None, None):
1175
 
                    raise DirstateCorrupt(self.state._filename,
 
1146
                    raise errors.CorruptDirstate(self.state._filename,
1176
1147
                        "entry '%s/%s' is considered renamed from %r"
1177
1148
                        " but source does not exist\n"
1178
1149
                        "entry: %s" % (entry[0][0], entry[0][1], old_path, entry))
1191
1162
                        old_path = path = self.pathjoin(old_dirname, old_basename)
1192
1163
                    file_id = entry[0][2]
1193
1164
                    self.new_dirname_to_file_id[path] = file_id
1194
 
                    if source_minikind != b'd':
 
1165
                    if source_minikind != c'd':
1195
1166
                        content_change = 1
1196
1167
                    else:
1197
1168
                        # directories have no fingerprint
1198
1169
                        content_change = 0
1199
1170
                    target_exec = False
1200
1171
                elif target_kind == 'file':
1201
 
                    if source_minikind != b'f':
 
1172
                    if source_minikind != c'f':
1202
1173
                        content_change = 1
1203
1174
                    else:
1204
1175
                        # Check the sha. We can't just rely on the size as
1220
1191
                    else:
1221
1192
                        target_exec = target_details[3]
1222
1193
                elif target_kind == 'symlink':
1223
 
                    if source_minikind != b'l':
 
1194
                    if source_minikind != c'l':
1224
1195
                        content_change = 1
1225
1196
                    else:
1226
1197
                        content_change = (link_or_sha1 != source_details[1])
1227
1198
                    target_exec = False
1228
1199
                elif target_kind == 'tree-reference':
1229
 
                    if source_minikind != b't':
 
1200
                    if source_minikind != c't':
1230
1201
                        content_change = 1
1231
1202
                    else:
1232
1203
                        content_change = 0
1235
1206
                    if path is None:
1236
1207
                        path = self.pathjoin(old_dirname, old_basename)
1237
1208
                    raise errors.BadFileKindError(path, path_info[2])
1238
 
            if source_minikind == b'd':
 
1209
            if source_minikind == c'd':
1239
1210
                if path is None:
1240
1211
                    old_path = path = self.pathjoin(old_dirname, old_basename)
1241
1212
                if file_id is None:
1248
1219
            else:
1249
1220
                try:
1250
1221
                    source_parent_id = self.old_dirname_to_file_id[old_dirname]
1251
 
                except KeyError, _:
 
1222
                except KeyError:
1252
1223
                    source_parent_entry = self.state._get_entry(self.source_index,
1253
1224
                                                           path_utf8=old_dirname)
1254
1225
                    source_parent_id = source_parent_entry[0][2]
1265
1236
            else:
1266
1237
                try:
1267
1238
                    target_parent_id = self.new_dirname_to_file_id[new_dirname]
1268
 
                except KeyError, _:
 
1239
                except KeyError:
1269
1240
                    # TODO: We don't always need to do the lookup, because the
1270
1241
                    #       parent entry will be the same as the source entry.
1271
1242
                    target_parent_entry = self.state._get_entry(self.target_index,
1303
1274
                    else:
1304
1275
                        path_u = self.utf8_decode(path)[0]
1305
1276
                source_kind = _minikind_to_kind(source_minikind)
1306
 
                return TreeChange(entry[0][2],
 
1277
                return (entry[0][2],
1307
1278
                       (old_path_u, path_u),
1308
1279
                       content_change,
1309
1280
                       (True, True),
1311
1282
                       (self.utf8_decode(old_basename)[0], self.utf8_decode(entry[0][1])[0]),
1312
1283
                       (source_kind, target_kind),
1313
1284
                       (source_exec, target_exec)), changed
1314
 
        elif source_minikind == b'a' and _versioned_minikind(target_minikind):
 
1285
        elif source_minikind == c'a' and _versioned_minikind(target_minikind):
1315
1286
            # looks like a new file
1316
1287
            path = self.pathjoin(entry[0][0], entry[0][1])
1317
1288
            # parent id is the entry for the path in the target tree
1319
1290
            parent_entry = self.state._get_entry(self.target_index,
1320
1291
                                                 path_utf8=entry[0][0])
1321
1292
            if parent_entry is None:
1322
 
                raise DirstateCorrupt(self.state,
 
1293
                raise errors.DirstateCorrupt(self.state,
1323
1294
                    "We could not find the parent entry in index %d"
1324
1295
                    " for the entry: %s"
1325
1296
                    % (self.target_index, entry[0]))
1336
1307
                        and S_IXUSR & path_info[3].st_mode)
1337
1308
                else:
1338
1309
                    target_exec = target_details[3]
1339
 
                return TreeChange(entry[0][2],
 
1310
                return (entry[0][2],
1340
1311
                       (None, self.utf8_decode(path)[0]),
1341
1312
                       True,
1342
1313
                       (False, True),
1346
1317
                       (None, target_exec)), True
1347
1318
            else:
1348
1319
                # Its a missing file, report it as such.
1349
 
                return TreeChange(entry[0][2],
 
1320
                return (entry[0][2],
1350
1321
                       (None, self.utf8_decode(path)[0]),
1351
1322
                       False,
1352
1323
                       (False, True),
1354
1325
                       (None, self.utf8_decode(entry[0][1])[0]),
1355
1326
                       (None, None),
1356
1327
                       (None, False)), True
1357
 
        elif _versioned_minikind(source_minikind) and target_minikind == b'a':
 
1328
        elif _versioned_minikind(source_minikind) and target_minikind == c'a':
1358
1329
            # unversioned, possibly, or possibly not deleted: we dont care.
1359
1330
            # if its still on disk, *and* theres no other entry at this
1360
1331
            # path [we dont know this in this routine at the moment -
1364
1335
            parent_id = self.state._get_entry(self.source_index, path_utf8=entry[0][0])[0][2]
1365
1336
            if parent_id == entry[0][2]:
1366
1337
                parent_id = None
1367
 
            return TreeChange(
1368
 
                   entry[0][2],
 
1338
            return (entry[0][2],
1369
1339
                   (self.utf8_decode(old_path)[0], None),
1370
1340
                   True,
1371
1341
                   (True, False),
1373
1343
                   (self.utf8_decode(entry[0][1])[0], None),
1374
1344
                   (_minikind_to_kind(source_minikind), None),
1375
1345
                   (source_details[3], None)), True
1376
 
        elif _versioned_minikind(source_minikind) and target_minikind == b'r':
 
1346
        elif _versioned_minikind(source_minikind) and target_minikind == c'r':
1377
1347
            # a rename; could be a true rename, or a rename inherited from
1378
1348
            # a renamed parent. TODO: handle this efficiently. Its not
1379
1349
            # common case to rename dirs though, so a correct but slow
1380
1350
            # implementation will do.
1381
1351
            if (not self.doing_consistency_expansion and 
1382
 
                not is_inside_any(self.searched_specific_files,
 
1352
                not osutils.is_inside_any(self.searched_specific_files,
1383
1353
                    target_details[1])):
1384
1354
                self.search_specific_files.add(target_details[1])
1385
1355
                # We don't expand the specific files parents list here as
1386
1356
                # the path is absent in target and won't create a delta with
1387
1357
                # missing parent.
1388
 
        elif ((source_minikind == b'r' or source_minikind == b'a') and
1389
 
              (target_minikind == b'r' or target_minikind == b'a')):
 
1358
        elif ((source_minikind == c'r' or source_minikind == c'a') and
 
1359
              (target_minikind == c'r' or target_minikind == c'a')):
1390
1360
            # neither of the selected trees contain this path,
1391
1361
            # so skip over it. This is not currently directly tested, but
1392
1362
            # is indirectly via test_too_much.TestCommands.test_conflicts.
1411
1381
 
1412
1382
        :param result: A result tuple.
1413
1383
        """
1414
 
        if not self.partial or not result.file_id:
 
1384
        if not self.partial or not result[0]:
1415
1385
            return 0
1416
 
        self.seen_ids.add(result.file_id)
1417
 
        new_path = result.path[1]
 
1386
        self.seen_ids.add(result[0])
 
1387
        new_path = result[1][1]
1418
1388
        if new_path:
1419
1389
            # Not the root and not a delete: queue up the parents of the path.
1420
1390
            self.search_specific_file_parents.update(
1421
1391
                osutils.parent_directories(new_path.encode('utf8')))
1422
1392
            # Add the root directory which parent_directories does not
1423
1393
            # provide.
1424
 
            self.search_specific_file_parents.add(b'')
 
1394
            self.search_specific_file_parents.add('')
1425
1395
        return 0
1426
1396
 
1427
1397
    cdef int _update_current_block(self) except -1:
1428
1398
        if (self.block_index < len(self.state._dirblocks) and
1429
 
            is_inside(self.current_root, self.state._dirblocks[self.block_index][0])):
 
1399
            osutils.is_inside(self.current_root, self.state._dirblocks[self.block_index][0])):
1430
1400
            self.current_block = self.state._dirblocks[self.block_index]
1431
1401
            self.current_block_list = self.current_block[1]
1432
1402
            self.current_block_pos = 0
1488
1458
        # TODO: jam 20070516 - Avoid the _get_entry lookup overhead by
1489
1459
        #       keeping a cache of directories that we have seen.
1490
1460
        cdef object current_dirname, current_blockname
1491
 
        cdef char * current_dirname_c
1492
 
        cdef char * current_blockname_c
 
1461
        cdef char * current_dirname_c, * current_blockname_c
1493
1462
        cdef int advance_entry, advance_path
1494
1463
        cdef int path_handled
1495
1464
        searched_specific_files = self.searched_specific_files
1509
1478
            # interface doesn't require it.
1510
1479
            try:
1511
1480
                self.current_root = self.search_specific_files.pop()
1512
 
            except KeyError, _:
 
1481
            except KeyError:
1513
1482
                raise StopIteration()
1514
1483
            self.searched_specific_files.add(self.current_root)
1515
1484
            # process the entries for this containing directory: the rest will be
1528
1497
                    # some other random error: hand it up.
1529
1498
                    raise
1530
1499
            else:
1531
 
                self.root_dir_info = (b'', self.current_root,
 
1500
                self.root_dir_info = ('', self.current_root,
1532
1501
                    osutils.file_kind_from_stat_mode(root_stat.st_mode), root_stat,
1533
1502
                    self.root_abspath)
1534
1503
                if self.root_dir_info[2] == 'directory':
1562
1531
                new_executable = bool(
1563
1532
                    stat.S_ISREG(self.root_dir_info[3].st_mode)
1564
1533
                    and stat.S_IEXEC & self.root_dir_info[3].st_mode)
1565
 
                return TreeChange(
1566
 
                       None,
 
1534
                return (None,
1567
1535
                       (None, self.current_root_unicode),
1568
1536
                       True,
1569
1537
                       (False, False),
1585
1553
                    prefix=self.current_root)
1586
1554
                self.path_index = 0
1587
1555
                try:
1588
 
                    self.current_dir_info = next(self.dir_iterator)
 
1556
                    self.current_dir_info = self.dir_iterator.next()
1589
1557
                    self.current_dir_list = self.current_dir_info[1]
1590
1558
                except OSError, e:
1591
1559
                    # there may be directories in the inventory even though
1599
1567
                        #            and e.winerror == ERROR_DIRECTORY
1600
1568
                        try:
1601
1569
                            e_winerror = e.winerror
1602
 
                        except AttributeError, _:
 
1570
                        except AttributeError:
1603
1571
                            e_winerror = None
1604
1572
                        win_errors = (ERROR_DIRECTORY, ERROR_PATH_NOT_FOUND)
1605
1573
                        if (e.errno in win_errors or e_winerror in win_errors):
1610
1578
                    else:
1611
1579
                        raise
1612
1580
                else:
1613
 
                    if self.current_dir_info[0][0] == b'':
 
1581
                    if self.current_dir_info[0][0] == '':
1614
1582
                        # remove .bzr from iteration
1615
 
                        bzr_index = self.bisect_left(self.current_dir_list, (b'.bzr',))
1616
 
                        if self.current_dir_list[bzr_index][0] != b'.bzr':
 
1583
                        bzr_index = self.bisect_left(self.current_dir_list, ('.bzr',))
 
1584
                        if self.current_dir_list[bzr_index][0] != '.bzr':
1617
1585
                            raise AssertionError()
1618
1586
                        del self.current_dir_list[bzr_index]
1619
 
            initial_key = (self.current_root, b'', b'')
 
1587
            initial_key = (self.current_root, '', '')
1620
1588
            self.block_index, _ = self.state._find_block_index_from_key(initial_key)
1621
1589
            if self.block_index == 0:
1622
1590
                # we have processed the total root already, but because the
1633
1601
                # Work around pyrex broken heuristic - current_dirname has
1634
1602
                # the same scope as current_dirname_c
1635
1603
                current_dirname = self.current_dir_info[0][0]
1636
 
                current_dirname_c = PyBytes_AS_STRING_void(
 
1604
                current_dirname_c = PyString_AS_STRING_void(
1637
1605
                    <void *>current_dirname)
1638
1606
                current_blockname = self.current_block[0]
1639
 
                current_blockname_c = PyBytes_AS_STRING_void(
 
1607
                current_blockname_c = PyString_AS_STRING_void(
1640
1608
                    <void *>current_blockname)
1641
1609
                # In the python generator we evaluate this if block once per
1642
1610
                # dir+block; because we reenter in the pyrex version its being
1643
1611
                # evaluated once per path: we could cache the result before
1644
1612
                # doing the while loop and probably save time.
1645
1613
                if _cmp_by_dirs(current_dirname_c,
1646
 
                    PyBytes_Size(current_dirname),
 
1614
                    PyString_Size(current_dirname),
1647
1615
                    current_blockname_c,
1648
 
                    PyBytes_Size(current_blockname)) < 0:
 
1616
                    PyString_Size(current_blockname)) < 0:
1649
1617
                    # filesystem data refers to paths not covered by the
1650
1618
                    # dirblock.  this has two possibilities:
1651
1619
                    # A) it is versioned but empty, so there is no block for it
1674
1642
                            new_executable = bool(
1675
1643
                                stat.S_ISREG(current_path_info[3].st_mode)
1676
1644
                                and stat.S_IEXEC & current_path_info[3].st_mode)
1677
 
                            return TreeChange(
1678
 
                                None,
 
1645
                            return (None,
1679
1646
                                (None, self.utf8_decode(current_path_info[0])[0]),
1680
1647
                                True,
1681
1648
                                (False, False),
1687
1654
                    self.path_index = 0
1688
1655
                    self.current_dir_list = None
1689
1656
                    try:
1690
 
                        self.current_dir_info = next(self.dir_iterator)
 
1657
                        self.current_dir_info = self.dir_iterator.next()
1691
1658
                        self.current_dir_list = self.current_dir_info[1]
1692
 
                    except StopIteration, _:
 
1659
                    except StopIteration:
1693
1660
                        self.current_dir_info = None
1694
1661
                else: #(dircmp > 0)
1695
1662
                    # We have a dirblock entry for this location, but there
1750
1717
            cdef int cmp_result
1751
1718
            # cdef char * temp_str
1752
1719
            # cdef Py_ssize_t temp_str_length
1753
 
            # PyBytes_AsStringAndSize(disk_kind, &temp_str, &temp_str_length)
 
1720
            # PyString_AsStringAndSize(disk_kind, &temp_str, &temp_str_length)
1754
1721
            # if not strncmp(temp_str, "directory", temp_str_length):
1755
1722
            if (self.current_block is not None and
1756
1723
                self.current_block_pos < PyList_GET_SIZE(self.current_block_list)):
1777
1744
                advance_entry = -1
1778
1745
                advance_path = -1
1779
1746
                result = None
1780
 
                changed = None
1781
1747
                path_handled = 0
1782
1748
                if current_entry is None:
1783
1749
                    # unversioned -  the check for path_handled when the path
1790
1756
                else:
1791
1757
                    minikind = _minikind_from_string(
1792
1758
                        current_entry[1][self.target_index][0])
1793
 
                    cmp_result = ((current_path_info[1] > current_entry[0][1]) -
1794
 
                                  (current_path_info[1] < current_entry[0][1]))
1795
 
                    if (cmp_result or minikind == b'a' or minikind == b'r'):
 
1759
                    cmp_result = cmp(current_path_info[1], current_entry[0][1])
 
1760
                    if (cmp_result or minikind == c'a' or minikind == c'r'):
1796
1761
                        # The current path on disk doesn't match the dirblock
1797
1762
                        # record. Either the dirblock record is marked as
1798
1763
                        # absent/renamed, or the file on disk is not present at all
1838
1803
                                and stat.S_IEXEC & current_path_info[3].st_mode)
1839
1804
                            try:
1840
1805
                                relpath_unicode = self.utf8_decode(current_path_info[0])[0]
1841
 
                            except UnicodeDecodeError, _:
 
1806
                            except UnicodeDecodeError:
1842
1807
                                raise errors.BadFilenameEncoding(
1843
1808
                                    current_path_info[0], osutils._fs_enc)
1844
1809
                            if changed is not None:
1845
1810
                                raise AssertionError(
1846
1811
                                    "result is not None: %r" % result)
1847
 
                            result = TreeChange(
1848
 
                                None,
 
1812
                            result = (None,
1849
1813
                                (None, relpath_unicode),
1850
1814
                                True,
1851
1815
                                (False, False),
1885
1849
                self.path_index = 0
1886
1850
                self.current_dir_list = None
1887
1851
                try:
1888
 
                    self.current_dir_info = next(self.dir_iterator)
 
1852
                    self.current_dir_info = self.dir_iterator.next()
1889
1853
                    self.current_dir_list = self.current_dir_info[1]
1890
 
                except StopIteration, _:
 
1854
                except StopIteration:
1891
1855
                    self.current_dir_info = None
1892
1856
 
1893
1857
    cdef object _next_consistent_entries(self):
1894
1858
        """Grabs the next specific file parent case to consider.
1895
 
 
 
1859
        
1896
1860
        :return: A list of the results, each of which is as for _process_entry.
1897
1861
        """
1898
1862
        results = []
1904
1868
            if path_utf8 in self.searched_exact_paths:
1905
1869
                # We've examined this path.
1906
1870
                continue
1907
 
            if is_inside_any(self.searched_specific_files, path_utf8):
 
1871
            if osutils.is_inside_any(self.searched_specific_files, path_utf8):
1908
1872
                # We've examined this path.
1909
1873
                continue
1910
1874
            path_entries = self.state._entries_for_path(path_utf8)
1916
1880
            found_item = False
1917
1881
            for candidate_entry in path_entries:
1918
1882
                # Find entries present in target at this path:
1919
 
                if candidate_entry[1][self.target_index][0] not in (b'a', b'r'):
 
1883
                if candidate_entry[1][self.target_index][0] not in 'ar':
1920
1884
                    found_item = True
1921
1885
                    selected_entries.append(candidate_entry)
1922
1886
                # Find entries present in source at this path:
1923
1887
                elif (self.source_index is not None and
1924
 
                    candidate_entry[1][self.source_index][0] not in (b'a', b'r')):
 
1888
                    candidate_entry[1][self.source_index][0] not in 'ar'):
1925
1889
                    found_item = True
1926
 
                    if candidate_entry[1][self.target_index][0] == b'a':
 
1890
                    if candidate_entry[1][self.target_index][0] == 'a':
1927
1891
                        # Deleted, emit it here.
1928
1892
                        selected_entries.append(candidate_entry)
1929
1893
                    else:
1949
1913
                # expansion.
1950
1914
                if changed:
1951
1915
                    self._gather_result_for_consistency(result)
1952
 
                    if (result.kind[0] == 'directory' and
1953
 
                        result.kind[1] != 'directory'):
 
1916
                    if (result[6][0] == 'directory' and
 
1917
                        result[6][1] != 'directory'):
1954
1918
                        # This stopped being a directory, the old children have
1955
1919
                        # to be included.
1956
 
                        if entry[1][self.source_index][0] == b'r':
 
1920
                        if entry[1][self.source_index][0] == 'r':
1957
1921
                            # renamed, take the source path
1958
1922
                            entry_path_utf8 = entry[1][self.source_index][1]
1959
1923
                        else:
1960
1924
                            entry_path_utf8 = path_utf8
1961
 
                        initial_key = (entry_path_utf8, b'', b'')
 
1925
                        initial_key = (entry_path_utf8, '', '')
1962
1926
                        block_index, _ = self.state._find_block_index_from_key(
1963
1927
                            initial_key)
1964
1928
                        if block_index == 0:
1967
1931
                        current_block = None
1968
1932
                        if block_index < len(self.state._dirblocks):
1969
1933
                            current_block = self.state._dirblocks[block_index]
1970
 
                            if not is_inside(
 
1934
                            if not osutils.is_inside(
1971
1935
                                entry_path_utf8, current_block[0]):
1972
1936
                                # No entries for this directory at all.
1973
1937
                                current_block = None
1974
1938
                        if current_block is not None:
1975
1939
                            for entry in current_block[1]:
1976
 
                                if entry[1][self.source_index][0] in (b'a', b'r'):
 
1940
                                if entry[1][self.source_index][0] in 'ar':
1977
1941
                                    # Not in the source tree, so doesn't have to be
1978
1942
                                    # included.
1979
1943
                                    continue
1999
1963
                return None
2000
1964
            else:
2001
1965
                raise
2002
 
        utf8_basename = utf8_path.rsplit(b'/', 1)[-1]
 
1966
        utf8_basename = utf8_path.rsplit('/', 1)[-1]
2003
1967
        dir_info = (utf8_path, utf8_basename,
2004
1968
            osutils.file_kind_from_stat_mode(stat.st_mode), stat,
2005
1969
            abspath)