78
78
# will automatically Py_INCREF and Py_DECREF when appropriate. But for some
79
79
# inner loops, we don't need to do that at all, as the reference only lasts for
80
80
# a very short time.
81
# Note that the C API GetItem calls borrow references, so pyrex does the wrong
82
# thing if you declare e.g. object PyList_GetItem(object lst, int index) - you
83
# need to manually Py_INCREF yourself.
81
84
cdef extern from "Python.h":
82
85
ctypedef int Py_ssize_t
83
86
ctypedef struct PyObject:
85
88
int PyList_Append(object lst, object item) except -1
86
89
void *PyList_GetItem_object_void "PyList_GET_ITEM" (object lst, int index)
87
90
void *PyList_GetItem_void_void "PyList_GET_ITEM" (void * lst, int index)
91
object PyList_GET_ITEM(object lst, Py_ssize_t index)
88
92
int PyList_CheckExact(object)
93
Py_ssize_t PyList_GET_SIZE (object p)
90
95
void *PyTuple_GetItem_void_void "PyTuple_GET_ITEM" (void* tpl, int index)
91
96
object PyTuple_GetItem_void_object "PyTuple_GET_ITEM" (void* tpl, int index)
97
object PyTuple_GET_ITEM(object tpl, Py_ssize_t index)
93
100
char *PyString_AsString(object p)
94
101
char *PyString_AsString_obj "PyString_AsString" (PyObject *string)
95
102
char *PyString_AS_STRING_void "PyString_AS_STRING" (void *p)
103
int PyString_AsStringAndSize(object str, char **buffer, Py_ssize_t *length) except -1
96
104
object PyString_FromString(char *)
97
105
object PyString_FromStringAndSize(char *, Py_ssize_t)
98
106
int PyString_Size(object p)
964
971
cdef int block_index
965
972
cdef object current_block
966
973
cdef int current_block_pos
974
cdef object current_block_list
967
975
cdef object current_dir_info
976
cdef object current_dir_list
968
978
cdef object root_dir_info
970
979
cdef object bisect_left
972
981
def __init__(self, include_unchanged, use_filesystem_for_exec,
1007
1016
self.dir_iterator = None
1008
1017
self.block_index = -1
1009
1018
self.current_block = None
1019
self.current_block_list = None
1010
1020
self.current_block_pos = -1
1011
1021
self.current_dir_info = None
1022
self.current_dir_list = None
1012
1023
self.path_index = 0
1013
1024
self.root_dir_info = None
1014
1025
self.bisect_left = bisect.bisect_left
1291
1302
if (self.block_index < len(self.state._dirblocks) and
1292
1303
osutils.is_inside(self.current_root, self.state._dirblocks[self.block_index][0])):
1293
1304
self.current_block = self.state._dirblocks[self.block_index]
1305
self.current_block_list = self.current_block[1]
1294
1306
self.current_block_pos = 0
1296
1308
self.current_block = None
1309
self.current_block_list = None
1298
1311
def __next__(self):
1299
1312
# Simple thunk to allow tail recursion without pyrex confusion
1397
1411
# (tail recursion, can do a loop once the full structure is
1399
1413
return self._iter_next()
1400
self.path_handled = 0
1401
1415
self.root_entries_pos = 0
1402
1416
# XXX Clarity: This loop is duplicated a out the self.current_root
1403
1417
# is None guard above: if we return from it, it completes there
1404
1418
# (and the following if block cannot trigger because
1405
# self.path_handled must be true, so the if block is not
1419
# path_handled must be true, so the if block is not # duplicated.
1407
1420
while self.root_entries_pos < self.root_entries_len:
1408
1421
entry = self.root_entries[self.root_entries_pos]
1409
1422
self.root_entries_pos = self.root_entries_pos + 1
1410
1423
result = self._process_entry(entry, self.root_dir_info)
1411
1424
if result is not None:
1412
self.path_handled = -1
1413
1426
if result is not self.uninteresting:
1415
1428
# handle unversioned specified paths:
1416
if self.want_unversioned and not self.path_handled and self.root_dir_info:
1429
if self.want_unversioned and not path_handled and self.root_dir_info:
1417
1430
new_executable = bool(
1418
1431
stat.S_ISREG(self.root_dir_info[3].st_mode)
1419
1432
and stat.S_IEXEC & self.root_dir_info[3].st_mode)
1464
1479
if self.current_dir_info[0][0] == '':
1465
1480
# remove .bzr from iteration
1466
bzr_index = self.bisect_left(self.current_dir_info[1], ('.bzr',))
1467
if self.current_dir_info[1][bzr_index][0] != '.bzr':
1481
bzr_index = self.bisect_left(self.current_dir_list, ('.bzr',))
1482
if self.current_dir_list[bzr_index][0] != '.bzr':
1468
1483
raise AssertionError()
1469
del self.current_dir_info[1][bzr_index]
1484
del self.current_dir_list[bzr_index]
1470
1485
initial_key = (self.current_root, '', '')
1471
1486
self.block_index, _ = self.state._find_block_index_from_key(initial_key)
1472
1487
if self.block_index == 0:
1506
1522
# if (B) then we should ignore it, because we don't
1507
1523
# recurse into unknown directories.
1508
1524
# We are doing a loop
1509
while self.path_index < len(self.current_dir_info[1]):
1510
current_path_info = self.current_dir_info[1][self.path_index]
1525
while self.path_index < len(self.current_dir_list):
1526
current_path_info = self.current_dir_list[self.path_index]
1511
1527
# dont descend into this unversioned path if it is
1513
1529
if current_path_info[2] in ('directory',
1514
1530
'tree-reference'):
1515
del self.current_dir_info[1][self.path_index]
1531
del self.current_dir_list[self.path_index]
1516
1532
self.path_index = self.path_index - 1
1517
1533
self.path_index = self.path_index + 1
1518
1534
if self.want_unversioned:
1546
1564
# because that should have already been handled, but we
1547
1565
# need to handle all of the files that are contained
1549
while self.current_block_pos < len(self.current_block[1]):
1550
current_entry = self.current_block[1][self.current_block_pos]
1567
while self.current_block_pos < len(self.current_block_list):
1568
current_entry = self.current_block_list[self.current_block_pos]
1551
1569
self.current_block_pos = self.current_block_pos + 1
1552
1570
# entry referring to file not present on disk.
1553
1571
# advance the entry only, after processing.
1558
1576
self.block_index = self.block_index + 1
1559
1577
self._update_current_block()
1560
1578
continue # next loop-on-block/dir
1579
result = self._loop_one_block()
1580
if result is not None:
1582
if len(self.search_specific_files):
1583
# More supplied paths to process
1584
self.current_root = None
1585
return self._iter_next()
1586
raise StopIteration()
1588
cdef object _maybe_tree_ref(self, current_path_info):
1589
if self.tree._directory_is_tree_reference(
1590
self.utf8_decode(current_path_info[0])[0]):
1591
return current_path_info[:2] + \
1592
('tree-reference',) + current_path_info[3:]
1594
return current_path_info
1596
cdef object _loop_one_block(self):
1561
1597
# current_dir_info and current_block refer to the same directory -
1562
1598
# this is the common case code.
1563
1599
# Assign local variables for current path and entry:
1564
if (self.current_block and
1565
self.current_block_pos < len(self.current_block[1])):
1566
current_entry = self.current_block[1][self.current_block_pos]
1600
cdef object current_entry
1601
cdef object current_path_info
1602
cdef int path_handled
1603
# cdef char * temp_str
1604
# cdef Py_ssize_t temp_str_length
1605
# PyString_AsStringAndSize(disk_kind, &temp_str, &temp_str_length)
1606
# if not strncmp(temp_str, "directory", temp_str_length):
1607
if (self.current_block is not None and
1608
self.current_block_pos < PyList_GET_SIZE(self.current_block_list)):
1609
current_entry = PyList_GET_ITEM(self.current_block_list,
1610
self.current_block_pos)
1612
Py_INCREF(current_entry)
1568
1614
current_entry = None
1569
if (self.current_dir_info and
1570
self.path_index < len(self.current_dir_info[1])):
1571
current_path_info = self.current_dir_info[1][self.path_index]
1572
if current_path_info[2] == 'directory':
1573
if self.tree._directory_is_tree_reference(
1574
self.utf8_decode(current_path_info[0])[0]):
1575
current_path_info = current_path_info[:2] + \
1576
('tree-reference',) + current_path_info[3:]
1615
if (self.current_dir_info is not None and
1616
self.path_index < PyList_GET_SIZE(self.current_dir_list)):
1617
current_path_info = PyList_GET_ITEM(self.current_dir_list,
1620
Py_INCREF(current_path_info)
1621
disk_kind = PyTuple_GET_ITEM(current_path_info, 2)
1623
Py_INCREF(disk_kind)
1624
if disk_kind == "directory":
1625
current_path_info = self._maybe_tree_ref(current_path_info)
1578
1627
current_path_info = None
1579
self.path_handled = 0
1580
1628
while (current_entry is not None or current_path_info is not None):
1581
1629
advance_entry = -1
1582
1630
advance_path = -1
1584
1633
if current_entry is None:
1585
1634
# unversioned - the check for path_handled when the path
1586
1635
# is advanced will yield this path if needed.
1617
1666
result = self._process_entry(current_entry, current_path_info)
1618
1667
if result is not None:
1619
self.path_handled = -1
1620
1669
if result is self.uninteresting:
1622
1671
# >- loop control starts here:
1624
1673
if advance_entry and current_entry is not None:
1625
1674
self.current_block_pos = self.current_block_pos + 1
1626
if self.current_block_pos < len(self.current_block[1]):
1627
current_entry = self.current_block[1][self.current_block_pos]
1675
if self.current_block_pos < PyList_GET_SIZE(self.current_block_list):
1676
current_entry = self.current_block_list[self.current_block_pos]
1629
1678
current_entry = None
1631
1680
if advance_path and current_path_info is not None:
1632
if not self.path_handled:
1681
if not path_handled:
1633
1682
# unversioned in all regards
1634
1683
if self.want_unversioned:
1635
1684
new_executable = bool(
1654
1703
# dont descend into this unversioned path if it is
1656
1705
if current_path_info[2] in ('directory'):
1657
del self.current_dir_info[1][self.path_index]
1706
del self.current_dir_list[self.path_index]
1658
1707
self.path_index = self.path_index - 1
1659
1708
# dont descend the disk iterator into any tree
1661
1710
if current_path_info[2] == 'tree-reference':
1662
del self.current_dir_info[1][self.path_index]
1711
del self.current_dir_list[self.path_index]
1663
1712
self.path_index = self.path_index - 1
1664
1713
self.path_index = self.path_index + 1
1665
if self.path_index < len(self.current_dir_info[1]):
1666
current_path_info = self.current_dir_info[1][self.path_index]
1714
if self.path_index < len(self.current_dir_list):
1715
current_path_info = self.current_dir_list[self.path_index]
1667
1716
if current_path_info[2] == 'directory':
1668
if self.tree._directory_is_tree_reference(
1669
current_path_info[0].decode('utf8')):
1670
current_path_info = current_path_info[:2] + \
1671
('tree-reference',) + current_path_info[3:]
1717
current_path_info = self._maybe_tree_ref(
1673
1720
current_path_info = None
1674
self.path_handled = 0
1675
1721
if result is not None:
1676
1722
# Found a result on this pass, yield it
1680
1726
self._update_current_block()
1681
1727
if self.current_dir_info is not None:
1682
1728
self.path_index = 0
1729
self.current_dir_list = None
1684
1731
self.current_dir_info = self.dir_iterator.next()
1732
self.current_dir_list = self.current_dir_info[1]
1685
1733
except StopIteration:
1686
1734
self.current_dir_info = None
1687
if len(self.search_specific_files):
1688
# More supplied paths to process
1689
self.current_root = None
1690
return self._iter_next()
1691
raise StopIteration()