1278
1277
def update_by_delta(self, delta):
1279
1278
"""Apply an inventory delta to the dirstate for tree 0
1281
This is the workhorse for apply_inventory_delta in dirstate based
1284
1280
:param delta: An inventory delta. See Inventory.apply_delta for
1287
1283
self._read_dirblocks_if_needed()
1288
encode = cache_utf8.encode
1289
1284
insertions = {}
1291
# Accumulate parent references (path_utf8, id), to check for parentless
1292
# items or items placed under files/links/tree-references. We get
1293
# references from every item in the delta that is not a deletion and
1294
# is not itself the root.
1296
# Added ids must not be in the dirstate already. This set holds those
1299
# This loop transforms the delta to single atomic operations that can
1300
# be executed and validated.
1301
for old_path, new_path, file_id, inv_entry in sorted(
1302
inventory._check_delta_unique_old_paths(
1303
inventory._check_delta_unique_new_paths(
1304
inventory._check_delta_ids_match_entry(
1305
inventory._check_delta_ids_are_valid(
1306
inventory._check_delta_new_path_entry_both_or_None(delta))))),
1286
for old_path, new_path, file_id, inv_entry in sorted(delta, reverse=True):
1308
1287
if (file_id in insertions) or (file_id in removals):
1309
raise errors.InconsistentDelta(old_path or new_path, file_id,
1288
raise AssertionError("repeated file id in delta %r" % (file_id,))
1311
1289
if old_path is not None:
1312
1290
old_path = old_path.encode('utf-8')
1313
1291
removals[file_id] = old_path
1315
new_ids.add(file_id)
1316
1292
if new_path is not None:
1317
if inv_entry is None:
1318
raise errors.InconsistentDelta(new_path, file_id,
1319
"new_path with no entry")
1320
1293
new_path = new_path.encode('utf-8')
1321
dirname_utf8, basename = osutils.split(new_path)
1323
parents.add((dirname_utf8, inv_entry.parent_id))
1324
key = (dirname_utf8, basename, file_id)
1294
dirname, basename = osutils.split(new_path)
1295
key = (dirname, basename, file_id)
1325
1296
minikind = DirState._kind_to_minikind[inv_entry.kind]
1326
1297
if minikind == 't':
1327
1298
fingerprint = inv_entry.reference_revision
1349
1320
child_basename)
1350
1321
insertions[child[0][2]] = (key, minikind, executable,
1351
1322
fingerprint, new_child_path)
1352
self._check_delta_ids_absent(new_ids, delta, 0)
1354
self._apply_removals(removals.iteritems())
1355
self._apply_insertions(insertions.values())
1357
self._after_delta_check_parents(parents, 0)
1358
except errors.BzrError, e:
1359
self._changes_aborted = True
1360
if 'integrity error' not in str(e):
1362
# _get_entry raises BzrError when a request is inconsistent; we
1363
# want such errors to be shown as InconsistentDelta - and that
1364
# fits the behaviour we trigger.
1365
raise errors.InconsistentDeltaDelta(delta, "error from _get_entry.")
1323
self._apply_removals(removals.values())
1324
self._apply_insertions(insertions.values())
1367
1326
def _apply_removals(self, removals):
1368
for file_id, path in sorted(removals, reverse=True,
1369
key=operator.itemgetter(1)):
1327
for path in sorted(removals, reverse=True):
1370
1328
dirname, basename = osutils.split(path)
1371
1329
block_i, entry_i, d_present, f_present = \
1372
1330
self._get_block_entry_index(dirname, basename, 0)
1374
entry = self._dirblocks[block_i][1][entry_i]
1376
self._changes_aborted = True
1377
raise errors.InconsistentDelta(path, file_id,
1378
"Wrong path for old path.")
1379
if not f_present or entry[1][0][0] in 'ar':
1380
self._changes_aborted = True
1381
raise errors.InconsistentDelta(path, file_id,
1382
"Wrong path for old path.")
1383
if file_id != entry[0][2]:
1384
self._changes_aborted = True
1385
raise errors.InconsistentDelta(path, file_id,
1386
"Attempt to remove path has wrong id - found %r."
1331
entry = self._dirblocks[block_i][1][entry_i]
1388
1332
self._make_absent(entry)
1389
1333
# See if we have a malformed delta: deleting a directory must not
1390
1334
# leave crud behind. This increases the number of bisects needed
1398
1342
# be due to it being in a parent tree, or a corrupt delta.
1399
1343
for child_entry in self._dirblocks[block_i][1]:
1400
1344
if child_entry[1][0][0] not in ('r', 'a'):
1401
self._changes_aborted = True
1402
1345
raise errors.InconsistentDelta(path, entry[0][2],
1403
1346
"The file id was deleted but its children were "
1404
1347
"not deleted.")
1406
1349
def _apply_insertions(self, adds):
1408
for key, minikind, executable, fingerprint, path_utf8 in sorted(adds):
1409
self.update_minimal(key, minikind, executable, fingerprint,
1410
path_utf8=path_utf8)
1411
except errors.NotVersionedError:
1412
self._changes_aborted = True
1413
raise errors.InconsistentDelta(path_utf8.decode('utf8'), key[2],
1350
for key, minikind, executable, fingerprint, path_utf8 in sorted(adds):
1351
self.update_minimal(key, minikind, executable, fingerprint,
1352
path_utf8=path_utf8)
1416
1354
def update_basis_by_delta(self, delta, new_revid):
1417
1355
"""Update the parents of this tree after a commit.
1461
1399
# At the same time, to reduce interface friction we convert the input
1462
1400
# inventory entries to dirstate.
1463
1401
root_only = ('', '')
1464
# Accumulate parent references (path_utf8, id), to check for parentless
1465
# items or items placed under files/links/tree-references. We get
1466
# references from every item in the delta that is not a deletion and
1467
# is not itself the root.
1469
# Added ids must not be in the dirstate already. This set holds those
1472
1402
for old_path, new_path, file_id, inv_entry in delta:
1473
if inv_entry is not None and file_id != inv_entry.file_id:
1474
raise errors.InconsistentDelta(new_path, file_id,
1475
"mismatched entry file_id %r" % inv_entry)
1476
if new_path is not None:
1477
if inv_entry is None:
1478
raise errors.InconsistentDelta(new_path, file_id,
1479
"new_path with no entry")
1480
new_path_utf8 = encode(new_path)
1481
# note the parent for validation
1482
dirname_utf8, basename_utf8 = osutils.split(new_path_utf8)
1484
parents.add((dirname_utf8, inv_entry.parent_id))
1485
1403
if old_path is None:
1486
1404
adds.append((None, encode(new_path), file_id,
1487
1405
inv_to_entry(inv_entry), True))
1488
new_ids.add(file_id)
1489
1406
elif new_path is None:
1490
1407
deletes.append((encode(old_path), None, file_id, None, True))
1491
1408
elif (old_path, new_path) != root_only:
1503
1420
# for 'r' items on every pass.
1504
1421
self._update_basis_apply_deletes(deletes)
1423
new_path_utf8 = encode(new_path)
1506
1424
# Split into an add/delete pair recursively.
1507
1425
adds.append((None, new_path_utf8, file_id,
1508
1426
inv_to_entry(inv_entry), False))
1534
1452
# of everything.
1535
1453
changes.append((encode(old_path), encode(new_path), file_id,
1536
1454
inv_to_entry(inv_entry)))
1537
self._check_delta_ids_absent(new_ids, delta, 1)
1539
# Finish expunging deletes/first half of renames.
1540
self._update_basis_apply_deletes(deletes)
1541
# Reinstate second half of renames and new paths.
1542
self._update_basis_apply_adds(adds)
1543
# Apply in-situ changes.
1544
self._update_basis_apply_changes(changes)
1546
self._after_delta_check_parents(parents, 1)
1547
except errors.BzrError, e:
1548
self._changes_aborted = True
1549
if 'integrity error' not in str(e):
1551
# _get_entry raises BzrError when a request is inconsistent; we
1552
# want such errors to be shown as InconsistentDelta - and that
1553
# fits the behaviour we trigger. Partof this is driven by dirstate
1554
# only supporting deltas that turn the basis into a closer fit to
1556
raise errors.InconsistentDeltaDelta(delta, "error from _get_entry.")
1456
# Finish expunging deletes/first half of renames.
1457
self._update_basis_apply_deletes(deletes)
1458
# Reinstate second half of renames and new paths.
1459
self._update_basis_apply_adds(adds)
1460
# Apply in-situ changes.
1461
self._update_basis_apply_changes(changes)
1558
1463
self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1559
1464
self._header_state = DirState.IN_MEMORY_MODIFIED
1560
1465
self._id_index = None
1563
def _check_delta_ids_absent(self, new_ids, delta, tree_index):
1564
"""Check that none of the file_ids in new_ids are present in a tree."""
1567
id_index = self._get_id_index()
1568
for file_id in new_ids:
1569
for key in id_index.get(file_id, []):
1570
block_i, entry_i, d_present, f_present = \
1571
self._get_block_entry_index(key[0], key[1], tree_index)
1573
# In a different tree
1575
entry = self._dirblocks[block_i][1][entry_i]
1576
if entry[0][2] != file_id:
1577
# Different file_id, so not what we want.
1579
# NB: No changes made before this helper is called, so no need
1580
# to set the _changes_aborted flag.
1581
raise errors.InconsistentDelta(
1582
("%s/%s" % key[0:2]).decode('utf8'), file_id,
1583
"This file_id is new in the delta but already present in "
1586
1468
def _update_basis_apply_adds(self, adds):
1587
1469
"""Apply a sequence of adds to tree 1 during update_basis_by_delta.
1653
1535
null = DirState.NULL_PARENT_DETAILS
1654
1536
for old_path, new_path, file_id, _, real_delete in deletes:
1655
1537
if real_delete != (new_path is None):
1656
self._changes_aborted = True
1657
1538
raise AssertionError("bad delete delta")
1658
1539
# the entry for this file_id must be in tree 1.
1659
1540
dirname, basename = osutils.split(old_path)
1692
1573
# it is being resurrected here, so blank it out temporarily.
1693
1574
self._dirblocks[block_index][1][entry_index][1][1] = null
1695
def _after_delta_check_parents(self, parents, index):
1696
"""Check that parents required by the delta are all intact.
1698
:param parents: An iterable of (path_utf8, file_id) tuples which are
1699
required to be present in tree 'index' at path_utf8 with id file_id
1701
:param index: The column in the dirstate to check for parents in.
1703
for dirname_utf8, file_id in parents:
1704
# Get the entry - the ensures that file_id, dirname_utf8 exists and
1705
# has the right file id.
1706
entry = self._get_entry(index, file_id, dirname_utf8)
1707
if entry[1] is None:
1708
self._changes_aborted = True
1709
raise errors.InconsistentDelta(dirname_utf8.decode('utf8'),
1710
file_id, "This parent is not present.")
1711
# Parents of things must be directories
1712
if entry[1][index][0] != 'd':
1713
self._changes_aborted = True
1714
raise errors.InconsistentDelta(dirname_utf8.decode('utf8'),
1715
file_id, "This parent is not a directory.")
1717
1576
def _observed_sha1(self, entry, sha1, stat_value,
1718
1577
_stat_to_minikind=_stat_to_minikind, _pack_stat=pack_stat):
1719
1578
"""Note the sha1 of a file.
1962
1821
self._read_dirblocks_if_needed()
1963
1822
if path_utf8 is not None:
1964
1823
if type(path_utf8) is not str:
1965
raise errors.BzrError('path_utf8 is not a str: %s %r'
1824
raise AssertionError('path_utf8 is not a str: %s %s'
1966
1825
% (type(path_utf8), path_utf8))
1967
1826
# path lookups are faster
1968
1827
dirname, basename = osutils.split(path_utf8)
2537
2393
new_iterator = new_inv.iter_entries_by_dir()
2538
2394
# we will be modifying the dirstate, so we need a stable iterator. In
2539
2395
# future we might write one, for now we just clone the state into a
2540
# list using a copy so that we see every original item and don't have
2541
# to adjust the position when items are inserted or deleted in the
2542
# underlying dirstate.
2396
# list - which is a shallow copy.
2543
2397
old_iterator = iter(list(self._iter_entries()))
2544
2398
# both must have roots so this is safe:
2545
2399
current_new = new_iterator.next()
2579
2433
# we make both end conditions explicit
2580
2434
if not current_old:
2581
2435
# old is finished: insert current_new into the state.
2583
trace.mutter("Appending from new '%s'.",
2584
new_path_utf8.decode('utf8'))
2585
2436
self.update_minimal(new_entry_key, current_new_minikind,
2586
2437
executable=current_new[1].executable,
2587
path_utf8=new_path_utf8, fingerprint=fingerprint,
2438
path_utf8=new_path_utf8, fingerprint=fingerprint)
2589
2439
current_new = advance(new_iterator)
2590
2440
elif not current_new:
2591
2441
# new is finished
2593
trace.mutter("Truncating from old '%s/%s'.",
2594
current_old[0][0].decode('utf8'),
2595
current_old[0][1].decode('utf8'))
2596
2442
self._make_absent(current_old)
2597
2443
current_old = advance(old_iterator)
2598
2444
elif new_entry_key == current_old[0]:
2605
2451
# kind has changed.
2606
2452
if (current_old[1][0][3] != current_new[1].executable or
2607
2453
current_old[1][0][0] != current_new_minikind):
2609
trace.mutter("Updating in-place change '%s'.",
2610
new_path_utf8.decode('utf8'))
2611
2454
self.update_minimal(current_old[0], current_new_minikind,
2612
2455
executable=current_new[1].executable,
2613
path_utf8=new_path_utf8, fingerprint=fingerprint,
2456
path_utf8=new_path_utf8, fingerprint=fingerprint)
2615
2457
# both sides are dealt with, move on
2616
2458
current_old = advance(old_iterator)
2617
2459
current_new = advance(new_iterator)
2620
2462
and new_entry_key[1:] < current_old[0][1:])):
2621
2463
# new comes before:
2622
2464
# add a entry for this and advance new
2624
trace.mutter("Inserting from new '%s'.",
2625
new_path_utf8.decode('utf8'))
2626
2465
self.update_minimal(new_entry_key, current_new_minikind,
2627
2466
executable=current_new[1].executable,
2628
path_utf8=new_path_utf8, fingerprint=fingerprint,
2467
path_utf8=new_path_utf8, fingerprint=fingerprint)
2630
2468
current_new = advance(new_iterator)
2632
2470
# we've advanced past the place where the old key would be,
2633
2471
# without seeing it in the new list. so it must be gone.
2635
trace.mutter("Deleting from old '%s/%s'.",
2636
current_old[0][0].decode('utf8'),
2637
current_old[0][1].decode('utf8'))
2638
2472
self._make_absent(current_old)
2639
2473
current_old = advance(old_iterator)
2640
2474
self._dirblock_state = DirState.IN_MEMORY_MODIFIED
2641
2475
self._id_index = None
2642
2476
self._packed_stat_index = None
2644
trace.mutter("set_state_from_inventory complete.")
2646
2478
def _make_absent(self, current_old):
2647
2479
"""Mark current_old - an entry - as absent for tree 0.
2696
2528
return last_reference
2698
2530
def update_minimal(self, key, minikind, executable=False, fingerprint='',
2699
packed_stat=None, size=0, path_utf8=None, fullscan=False):
2531
packed_stat=None, size=0, path_utf8=None):
2700
2532
"""Update an entry to the state in tree 0.
2702
2534
This will either create a new entry at 'key' or update an existing one.
2713
2545
:param size: Size information for new entry
2714
2546
:param path_utf8: key[0] + '/' + key[1], just passed in to avoid doing
2715
2547
extra computation.
2716
:param fullscan: If True then a complete scan of the dirstate is being
2717
done and checking for duplicate rows should not be done. This
2718
should only be set by set_state_from_inventory and similar methods.
2720
2549
If packed_stat and fingerprint are not given, they're invalidated in
2730
2559
new_details = (minikind, fingerprint, size, executable, packed_stat)
2731
2560
id_index = self._get_id_index()
2732
2561
if not present:
2733
# New record. Check there isn't a entry at this path already.
2735
low_index, _ = self._find_entry_index(key[0:2] + ('',), block)
2736
while low_index < len(block):
2737
entry = block[low_index]
2738
if entry[0][0:2] == key[0:2]:
2739
if entry[1][0][0] not in 'ar':
2740
# This entry has the same path (but a different id) as
2741
# the new entry we're adding, and is present in ths
2743
raise errors.InconsistentDelta(
2744
("%s/%s" % key[0:2]).decode('utf8'), key[2],
2745
"Attempt to add item at path already occupied by "
2746
"id %r" % entry[0][2])
2750
2562
# new entry, synthesis cross reference here,
2751
2563
existing_keys = id_index.setdefault(key[2], set())
2752
2564
if not existing_keys:
2757
2569
# grab one of them and use it to generate parent
2758
2570
# relocation/absent entries.
2759
2571
new_entry = key, [new_details]
2760
# existing_keys can be changed as we iterate.
2761
for other_key in tuple(existing_keys):
2572
for other_key in existing_keys:
2762
2573
# change the record at other to be a pointer to this new
2763
2574
# record. The loop looks similar to the change to
2764
2575
# relocations when updating an existing record but its not:
2765
2576
# the test for existing kinds is different: this can be
2766
2577
# factored out to a helper though.
2767
other_block_index, present = self._find_block_index_from_key(
2770
raise AssertionError('could not find block for %s' % (
2772
other_block = self._dirblocks[other_block_index][1]
2773
other_entry_index, present = self._find_entry_index(
2774
other_key, other_block)
2776
raise AssertionError(
2777
'update_minimal: could not find other entry for %s'
2578
other_block_index, present = self._find_block_index_from_key(other_key)
2580
raise AssertionError('could not find block for %s' % (other_key,))
2581
other_entry_index, present = self._find_entry_index(other_key,
2582
self._dirblocks[other_block_index][1])
2584
raise AssertionError('could not find entry for %s' % (other_key,))
2779
2585
if path_utf8 is None:
2780
2586
raise AssertionError('no path')
2781
# Turn this other location into a reference to the new
2782
# location. This also updates the aliased iterator
2783
# (current_old in set_state_from_inventory) so that the old
2784
# entry, if not already examined, is skipped over by that
2786
other_entry = other_block[other_entry_index]
2787
other_entry[1][0] = ('r', path_utf8, 0, False, '')
2788
self._maybe_remove_row(other_block, other_entry_index,
2587
self._dirblocks[other_block_index][1][other_entry_index][1][0] = \
2588
('r', path_utf8, 0, False, '')
2792
# adds a tuple to the new details for each column
2793
# - either by copying an existing relocation pointer inside that column
2794
# - or by creating a new pointer to the right row inside that column
2795
2590
num_present_parents = self._num_present_parents()
2796
if num_present_parents:
2797
other_key = list(existing_keys)[0]
2798
2591
for lookup_index in xrange(1, num_present_parents + 1):
2799
2592
# grab any one entry, use it to find the right path.
2800
2593
# TODO: optimise this to reduce memory use in highly
2807
2600
update_entry_index, present = \
2808
2601
self._find_entry_index(other_key, self._dirblocks[update_block_index][1])
2809
2602
if not present:
2810
raise AssertionError('update_minimal: could not find entry for %s' % (other_key,))
2603
raise AssertionError('could not find entry for %s' % (other_key,))
2811
2604
update_details = self._dirblocks[update_block_index][1][update_entry_index][1][lookup_index]
2812
2605
if update_details[0] in 'ar': # relocated, absent
2813
2606
# its a pointer or absent in lookup_index's tree, use
2860
2653
self._dirblock_state = DirState.IN_MEMORY_MODIFIED
2862
def _maybe_remove_row(self, block, index, id_index):
2863
"""Remove index if it is absent or relocated across the row.
2865
id_index is updated accordingly.
2867
present_in_row = False
2868
entry = block[index]
2869
for column in entry[1]:
2870
if column[0] not in 'ar':
2871
present_in_row = True
2873
if not present_in_row:
2875
id_index[entry[0][2]].remove(entry[0])
2877
2655
def _validate(self):
2878
2656
"""Check that invariants on the dirblock are correct.
3160
2938
False, DirState.NULLSTAT)
3161
2939
state._dirblock_state = DirState.IN_MEMORY_MODIFIED
3162
2940
return link_or_sha1
2941
update_entry = py_update_entry
3165
2944
class ProcessEntryPython(object):
3167
__slots__ = ["old_dirname_to_file_id", "new_dirname_to_file_id",
2946
__slots__ = ["old_dirname_to_file_id", "new_dirname_to_file_id", "uninteresting",
3168
2947
"last_source_parent", "last_target_parent", "include_unchanged",
3169
2948
"use_filesystem_for_exec", "utf8_decode", "searched_specific_files",
3170
2949
"search_specific_files", "state", "source_index", "target_index",
3175
2954
want_unversioned, tree):
3176
2955
self.old_dirname_to_file_id = {}
3177
2956
self.new_dirname_to_file_id = {}
2957
# Just a sentry, so that _process_entry can say that this
2958
# record is handled, but isn't interesting to process (unchanged)
2959
self.uninteresting = object()
3178
2960
# Using a list so that we can access the values and change them in
3179
2961
# nested scope. Each one is [path, file_id, entry]
3180
2962
self.last_source_parent = [None, None]
3203
2985
Basename is returned as a utf8 string because we expect this
3204
2986
tuple will be ignored, and don't want to take the time to
3206
:return: (iter_changes_result, changed). If the entry has not been
3207
handled then changed is None. Otherwise it is False if no content
3208
or metadata changes have occured, and None if any content or
3209
metadata change has occured. If self.include_unchanged is True then
3210
if changed is not None, iter_changes_result will always be a result
3211
tuple. Otherwise, iter_changes_result is None unless changed is
2988
:return: None if these don't match
2989
A tuple of information about the change, or
2990
the object 'uninteresting' if these match, but are
2991
basically identical.
3214
2993
if self.source_index is None:
3215
2994
source_details = DirState.NULL_PARENT_DETAILS
3283
3062
if source_minikind != 'f':
3284
3063
content_change = True
3286
# Check the sha. We can't just rely on the size as
3287
# content filtering may mean differ sizes actually
3288
# map to the same content
3289
if link_or_sha1 is None:
3291
statvalue, link_or_sha1 = \
3292
self.state._sha1_provider.stat_and_sha1(
3294
self.state._observed_sha1(entry, link_or_sha1,
3296
content_change = (link_or_sha1 != source_details[1])
3065
# If the size is the same, check the sha:
3066
if target_details[2] == source_details[2]:
3067
if link_or_sha1 is None:
3069
statvalue, link_or_sha1 = \
3070
self.state._sha1_provider.stat_and_sha1(
3072
self.state._observed_sha1(entry, link_or_sha1,
3074
content_change = (link_or_sha1 != source_details[1])
3076
# Size changed, so must be different
3077
content_change = True
3297
3078
# Target details is updated at update_entry time
3298
3079
if self.use_filesystem_for_exec:
3299
3080
# We don't need S_ISREG here, because we are sure
3359
3140
self.last_target_parent[1] = target_parent_id
3361
3142
source_exec = source_details[3]
3362
changed = (content_change
3143
if (self.include_unchanged
3363
3145
or source_parent_id != target_parent_id
3364
3146
or old_basename != entry[0][1]
3365
3147
or source_exec != target_exec
3367
if not changed and not self.include_unchanged:
3370
3149
if old_path is None:
3371
3150
old_path = path = pathjoin(old_dirname, old_basename)
3372
3151
old_path_u = self.utf8_decode(old_path)[0]
3385
3164
(source_parent_id, target_parent_id),
3386
3165
(self.utf8_decode(old_basename)[0], self.utf8_decode(entry[0][1])[0]),
3387
3166
(source_kind, target_kind),
3388
(source_exec, target_exec)), changed
3167
(source_exec, target_exec))
3169
return self.uninteresting
3389
3170
elif source_minikind in 'a' and target_minikind in 'fdlt':
3390
3171
# looks like a new file
3391
3172
path = pathjoin(entry[0][0], entry[0][1])
3440
3221
(parent_id, None),
3441
3222
(self.utf8_decode(entry[0][1])[0], None),
3442
3223
(DirState._minikind_to_kind[source_minikind], None),
3443
(source_details[3], None)), True
3224
(source_details[3], None))
3444
3225
elif source_minikind in 'fdlt' and target_minikind in 'r':
3445
3226
# a rename; could be a true rename, or a rename inherited from
3446
3227
# a renamed parent. TODO: handle this efficiently. Its not
3468
3249
utf8_decode = cache_utf8._utf8_decode
3469
3250
_cmp_by_dirs = cmp_by_dirs
3470
3251
_process_entry = self._process_entry
3252
uninteresting = self.uninteresting
3471
3253
search_specific_files = self.search_specific_files
3472
3254
searched_specific_files = self.searched_specific_files
3473
3255
splitpath = osutils.splitpath
3544
3326
path_handled = False
3545
3327
for entry in root_entries:
3546
result, changed = _process_entry(entry, root_dir_info)
3547
if changed is not None:
3328
result = _process_entry(entry, root_dir_info)
3329
if result is not None:
3548
3330
path_handled = True
3549
if changed or self.include_unchanged:
3331
if result is not uninteresting:
3551
3333
if self.want_unversioned and not path_handled and root_dir_info:
3552
3334
new_executable = bool(
3662
3444
for current_entry in current_block[1]:
3663
3445
# entry referring to file not present on disk.
3664
3446
# advance the entry only, after processing.
3665
result, changed = _process_entry(current_entry, None)
3666
if changed is not None:
3667
if changed or self.include_unchanged:
3447
result = _process_entry(current_entry, None)
3448
if result is not None:
3449
if result is not uninteresting:
3669
3451
block_index +=1
3670
3452
if (block_index < len(self.state._dirblocks) and
3701
3483
elif current_path_info is None:
3702
3484
# no path is fine: the per entry code will handle it.
3703
result, changed = _process_entry(current_entry, current_path_info)
3704
if changed is not None:
3705
if changed or self.include_unchanged:
3485
result = _process_entry(current_entry, current_path_info)
3486
if result is not None:
3487
if result is not uninteresting:
3707
3489
elif (current_entry[0][1] != current_path_info[1]
3708
3490
or current_entry[1][self.target_index][0] in 'ar'):
3722
3504
# entry referring to file not present on disk.
3723
3505
# advance the entry only, after processing.
3724
result, changed = _process_entry(current_entry, None)
3725
if changed is not None:
3726
if changed or self.include_unchanged:
3506
result = _process_entry(current_entry, None)
3507
if result is not None:
3508
if result is not uninteresting:
3728
3510
advance_path = False
3730
result, changed = _process_entry(current_entry, current_path_info)
3731
if changed is not None:
3512
result = _process_entry(current_entry, current_path_info)
3513
if result is not None:
3732
3514
path_handled = True
3733
if changed or self.include_unchanged:
3515
if result is not uninteresting:
3735
3517
if advance_entry and current_entry is not None:
3736
3518
entry_index += 1
3795
3577
current_dir_info = dir_iterator.next()
3796
3578
except StopIteration:
3797
3579
current_dir_info = None
3580
_process_entry = ProcessEntryPython
3800
3583
# Try to load the compiled form if possible
3802
from bzrlib._dirstate_helpers_pyx import (
3585
from bzrlib._dirstate_helpers_c import (
3586
_read_dirblocks_c as _read_dirblocks,
3587
bisect_dirblock_c as bisect_dirblock,
3588
_bisect_path_left_c as _bisect_path_left,
3589
_bisect_path_right_c as _bisect_path_right,
3590
cmp_by_dirs_c as cmp_by_dirs,
3808
3591
ProcessEntryC as _process_entry,
3809
3592
update_entry as update_entry,
3811
3594
except ImportError:
3812
3595
from bzrlib._dirstate_helpers_py import (
3596
_read_dirblocks_py as _read_dirblocks,
3597
bisect_dirblock_py as bisect_dirblock,
3598
_bisect_path_left_py as _bisect_path_left,
3599
_bisect_path_right_py as _bisect_path_right,
3600
cmp_by_dirs_py as cmp_by_dirs,
3819
# FIXME: It would be nice to be able to track moved lines so that the
3820
# corresponding python code can be moved to the _dirstate_helpers_py
3821
# module. I don't want to break the history for this important piece of
3822
# code so I left the code here -- vila 20090622
3823
update_entry = py_update_entry
3824
_process_entry = ProcessEntryPython