1008
1239
block_index += 1
1009
1240
if ids_to_unversion:
1010
1241
raise errors.NoSuchId(self, iter(ids_to_unversion).next())
1242
self._make_dirty(reset_inventory=False)
1012
1243
# have to change the legacy inventory too.
1013
1244
if self._inventory is not None:
1014
1245
for file_id in file_ids:
1015
1246
self._inventory.remove_recursive_id(file_id)
1017
1248
@needs_tree_write_lock
1249
def rename_one(self, from_rel, to_rel, after=False):
1250
"""See WorkingTree.rename_one"""
1252
WorkingTree.rename_one(self, from_rel, to_rel, after)
1254
@needs_tree_write_lock
1255
def apply_inventory_delta(self, changes):
1256
"""See MutableTree.apply_inventory_delta"""
1257
state = self.current_dirstate()
1258
state.update_by_delta(changes)
1259
self._make_dirty(reset_inventory=True)
1261
def update_basis_by_delta(self, new_revid, delta):
1262
"""See MutableTree.update_basis_by_delta."""
1263
if self.last_revision() == new_revid:
1264
raise AssertionError()
1265
self.current_dirstate().update_basis_by_delta(delta, new_revid)
1268
def _validate(self):
1269
self._dirstate._validate()
1271
@needs_tree_write_lock
1018
1272
def _write_inventory(self, inv):
1019
1273
"""Write inventory as the current inventory."""
1020
assert not self._dirty, "attempting to write an inventory when the dirstate is dirty will cause data loss"
1275
raise AssertionError("attempting to write an inventory when the "
1276
"dirstate is dirty will lose pending changes")
1021
1277
self.current_dirstate().set_state_from_inventory(inv)
1278
self._make_dirty(reset_inventory=False)
1279
if self._inventory is not None:
1280
self._inventory = inv
1026
class WorkingTreeFormat4(WorkingTreeFormat3):
1027
"""The first consolidated dirstate working tree format.
1030
- exists within a metadir controlling .bzr
1031
- includes an explicit version marker for the workingtree control
1032
files, separate from the BzrDir format
1033
- modifies the hash cache format
1034
- is new in bzr TODO FIXME SETBEFOREMERGE
1035
- uses a LockDir to guard access to it.
1038
def get_format_string(self):
1039
"""See WorkingTreeFormat.get_format_string()."""
1040
return "Bazaar Working Tree format 4\n"
1042
def get_format_description(self):
1043
"""See WorkingTreeFormat.get_format_description()."""
1044
return "Working tree format 4"
1046
def initialize(self, a_bzrdir, revision_id=None):
1284
class WorkingTree4(DirStateWorkingTree):
1285
"""This is the Format 4 working tree.
1287
This differs from WorkingTree3 by:
1288
- Having a consolidated internal dirstate, stored in a
1289
randomly-accessible sorted file on disk.
1290
- Not having a regular inventory attribute. One can be synthesized
1291
on demand but this is expensive and should be avoided.
1293
This is new in bzr 0.15.
1297
class WorkingTree5(DirStateWorkingTree):
1298
"""This is the Format 5 working tree.
1300
This differs from WorkingTree4 by:
1301
- Supporting content filtering.
1302
- Supporting a current view that may mask the set of files in a tree
1303
impacted by most user operations.
1305
This is new in bzr 1.11.
1309
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1310
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1311
accelerator_tree=None, hardlink=False):
1047
1312
"""See WorkingTreeFormat.initialize().
1049
revision_id allows creating a working tree at a different
1314
:param revision_id: allows creating a working tree at a different
1050
1315
revision than the branch is at.
1316
:param accelerator_tree: A tree which can be used for retrieving file
1317
contents more quickly than the revision tree, i.e. a workingtree.
1318
The revision tree will be used for cases where accelerator_tree's
1319
content is different.
1320
:param hardlink: If true, hard-link files from accelerator_tree,
1323
These trees get an initial random root id, if their repository supports
1324
rich root data, TREE_ROOT otherwise.
1052
revision_id = osutils.safe_revision_id(revision_id)
1053
1326
if not isinstance(a_bzrdir.transport, LocalTransport):
1054
1327
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1055
1328
transport = a_bzrdir.get_workingtree_transport(self)
1056
1329
control_files = self._open_control_files(a_bzrdir)
1057
1330
control_files.create_lock()
1058
1331
control_files.lock_write()
1059
control_files.put_utf8('format', self.get_format_string())
1060
branch = a_bzrdir.open_branch()
1332
transport.put_bytes('format', self.get_format_string(),
1333
mode=a_bzrdir._get_file_mode())
1334
if from_branch is not None:
1335
branch = from_branch
1337
branch = a_bzrdir.open_branch()
1061
1338
if revision_id is None:
1062
1339
revision_id = branch.last_revision()
1063
1340
local_path = transport.local_abspath('dirstate')
1341
# write out new dirstate (must exist when we create the tree)
1064
1342
state = dirstate.DirState.initialize(local_path)
1066
wt = WorkingTree4(a_bzrdir.root_transport.local_abspath('.'),
1345
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
1069
1348
_bzrdir=a_bzrdir,
1489
1973
all_versioned = False
1491
1975
if not all_versioned:
1492
raise errors.PathsNotVersionedError(paths)
1976
raise errors.PathsNotVersionedError(specific_files)
1493
1977
# -- remove redundancy in supplied specific_files to prevent over-scanning --
1494
search_specific_files = set()
1495
1978
for path in specific_files:
1496
1979
other_specific_files = specific_files.difference(set([path]))
1497
1980
if not osutils.is_inside_any(other_specific_files, path):
1498
1981
# this is a top level path, we must check it.
1499
1982
search_specific_files.add(path)
1501
# compare source_index and target_index at or under each element of search_specific_files.
1502
# follow the following comparison table. Note that we only want to do diff operations when
1503
# the target is fdl because thats when the walkdirs logic will have exposed the pathinfo
1507
# Source | Target | disk | action
1508
# r | fdl | | add source to search, add id path move and perform
1509
# | | | diff check on source-target
1510
# r | fdl | a | dangling file that was present in the basis.
1512
# r | a | | add source to search
1514
# r | r | | this path is present in a non-examined tree, skip.
1515
# r | r | a | this path is present in a non-examined tree, skip.
1516
# a | fdl | | add new id
1517
# a | fdl | a | dangling locally added file, skip
1518
# a | a | | not present in either tree, skip
1519
# a | a | a | not present in any tree, skip
1520
# a | r | | not present in either tree at this path, skip as it
1521
# | | | may not be selected by the users list of paths.
1522
# a | r | a | not present in either tree at this path, skip as it
1523
# | | | may not be selected by the users list of paths.
1524
# fdl | fdl | | content in both: diff them
1525
# fdl | fdl | a | deleted locally, but not unversioned - show as deleted ?
1526
# fdl | a | | unversioned: output deleted id for now
1527
# fdl | a | a | unversioned and deleted: output deleted id
1528
# fdl | r | | relocated in this tree, so add target to search.
1529
# | | | Dont diff, we will see an r,fd; pair when we reach
1530
# | | | this id at the other path.
1531
# fdl | r | a | relocated in this tree, so add target to search.
1532
# | | | Dont diff, we will see an r,fd; pair when we reach
1533
# | | | this id at the other path.
1535
# for all search_indexs in each path at or under each element of
1536
# search_specific_files, if the detail is relocated: add the id, and add the
1537
# relocated path as one to search if its not searched already. If the
1538
# detail is not relocated, add the id.
1539
searched_specific_files = set()
1540
NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
1541
# Using a list so that we can access the values and change them in
1542
# nested scope. Each one is [path, file_id, entry]
1543
last_source_parent = [None, None, None]
1544
last_target_parent = [None, None, None]
1546
def _process_entry(entry, path_info):
1547
"""Compare an entry and real disk to generate delta information.
1549
:param path_info: top_relpath, basename, kind, lstat, abspath for
1550
the path of entry. If None, then the path is considered absent.
1551
(Perhaps we should pass in a concrete entry for this ?)
1553
# TODO: when a parent has been renamed, dont emit path renames for children,
1554
if source_index is None:
1555
source_details = NULL_PARENT_DETAILS
1557
source_details = entry[1][source_index]
1558
target_details = entry[1][target_index]
1559
source_minikind = source_details[0]
1560
target_minikind = target_details[0]
1561
if source_minikind in 'fdlr' and target_minikind in 'fdl':
1562
# claimed content in both: diff
1563
# r | fdl | | add source to search, add id path move and perform
1564
# | | | diff check on source-target
1565
# r | fdl | a | dangling file that was present in the basis.
1567
if source_minikind in 'r':
1568
# add the source to the search path to find any children it
1569
# has. TODO ? : only add if it is a container ?
1570
if not osutils.is_inside_any(searched_specific_files,
1572
search_specific_files.add(source_details[1])
1573
# generate the old path; this is needed for stating later
1575
old_path = source_details[1]
1576
old_dirname, old_basename = os.path.split(old_path)
1577
path = pathjoin(entry[0][0], entry[0][1])
1578
old_entry = state._get_entry(source_index,
1580
# update the source details variable to be the real
1582
source_details = old_entry[1][source_index]
1583
source_minikind = source_details[0]
1585
old_dirname = entry[0][0]
1586
old_basename = entry[0][1]
1587
old_path = path = pathjoin(old_dirname, old_basename)
1588
if path_info is None:
1589
# the file is missing on disk, show as removed.
1590
old_path = pathjoin(entry[0][0], entry[0][1])
1591
content_change = True
1595
# source and target are both versioned and disk file is present.
1596
target_kind = path_info[2]
1597
if target_kind == 'directory':
1598
if source_minikind != 'd':
1599
content_change = True
1601
# directories have no fingerprint
1602
content_change = False
1604
elif target_kind == 'file':
1605
if source_minikind != 'f':
1606
content_change = True
1608
# has it changed? fast path: size, slow path: sha1.
1609
if source_details[2] != path_info[3].st_size:
1610
content_change = True
1612
# maybe the same. Get the hash
1613
new_hash = self.target._hashcache.get_sha1(
1615
content_change = (new_hash != source_details[1])
1617
stat.S_ISREG(path_info[3].st_mode)
1618
and stat.S_IEXEC & path_info[3].st_mode)
1619
elif target_kind == 'symlink':
1620
if source_minikind != 'l':
1621
content_change = True
1623
# TODO: check symlink supported for windows users
1624
# and grab from target state here.
1625
link_target = os.readlink(path_info[4])
1626
content_change = (link_target != source_details[1])
1629
raise Exception, "unknown kind %s" % path_info[2]
1630
# parent id is the entry for the path in the target tree
1631
if old_dirname == last_source_parent[0]:
1632
source_parent_id = last_source_parent[1]
1634
source_parent_entry = state._get_entry(source_index,
1635
path_utf8=old_dirname)
1636
source_parent_id = source_parent_entry[0][2]
1637
if source_parent_id == entry[0][2]:
1638
# This is the root, so the parent is None
1639
source_parent_id = None
1641
last_source_parent[0] = old_dirname
1642
last_source_parent[1] = source_parent_id
1643
last_source_parent[2] = source_parent_entry
1645
new_dirname = entry[0][0]
1646
if new_dirname == last_target_parent[0]:
1647
target_parent_id = last_target_parent[1]
1649
# TODO: We don't always need to do the lookup, because the
1650
# parent entry will be the same as the source entry.
1651
target_parent_entry = state._get_entry(target_index,
1652
path_utf8=new_dirname)
1653
target_parent_id = target_parent_entry[0][2]
1654
if target_parent_id == entry[0][2]:
1655
# This is the root, so the parent is None
1656
target_parent_id = None
1658
last_target_parent[0] = new_dirname
1659
last_target_parent[1] = target_parent_id
1660
last_target_parent[2] = target_parent_entry
1662
source_exec = source_details[3]
1663
path_unicode = utf8_decode(path)[0]
1664
return ((entry[0][2], path_unicode, content_change,
1666
(source_parent_id, target_parent_id),
1667
(old_basename, entry[0][1]),
1668
(_minikind_to_kind[source_minikind], target_kind),
1669
(source_exec, target_exec)),)
1670
elif source_minikind in 'a' and target_minikind in 'fdl':
1671
# looks like a new file
1672
if path_info is not None:
1673
path = pathjoin(entry[0][0], entry[0][1])
1674
# parent id is the entry for the path in the target tree
1675
# TODO: these are the same for an entire directory: cache em.
1676
parent_id = state._get_entry(target_index, path_utf8=entry[0][0])[0][2]
1677
if parent_id == entry[0][2]:
1680
new_executable = bool(
1681
stat.S_ISREG(path_info[3].st_mode)
1682
and stat.S_IEXEC & path_info[3].st_mode)
1683
path_unicode = utf8_decode(path)[0]
1684
return ((entry[0][2], path_unicode, True,
1687
(None, entry[0][1]),
1688
(None, path_info[2]),
1689
(None, new_executable)),)
1691
# but its not on disk: we deliberately treat this as just
1692
# never-present. (Why ?! - RBC 20070224)
1694
elif source_minikind in 'fdl' and target_minikind in 'a':
1695
# unversioned, possibly, or possibly not deleted: we dont care.
1696
# if its still on disk, *and* theres no other entry at this
1697
# path [we dont know this in this routine at the moment -
1698
# perhaps we should change this - then it would be an unknown.
1699
old_path = pathjoin(entry[0][0], entry[0][1])
1700
# parent id is the entry for the path in the target tree
1701
parent_id = state._get_entry(source_index, path_utf8=entry[0][0])[0][2]
1702
if parent_id == entry[0][2]:
1704
old_path_unicode = utf8_decode(old_path)[0]
1705
return ((entry[0][2], old_path_unicode, True,
1708
(entry[0][1], None),
1709
(_minikind_to_kind[source_minikind], None),
1710
(source_details[3], None)),)
1711
elif source_minikind in 'fdl' and target_minikind in 'r':
1712
# a rename; could be a true rename, or a rename inherited from
1713
# a renamed parent. TODO: handle this efficiently. Its not
1714
# common case to rename dirs though, so a correct but slow
1715
# implementation will do.
1716
if not osutils.is_inside_any(searched_specific_files, target_details[1]):
1717
search_specific_files.add(target_details[1])
1718
elif source_minikind in 'r' and target_minikind in 'r':
1719
# neither of the selected trees contain this file,
1720
# so skip over it. This is not currently directly tested, but
1721
# is indirectly via test_too_much.TestCommands.test_conflicts.
1724
print "*******", source_minikind, target_minikind
1725
import pdb;pdb.set_trace()
1727
while search_specific_files:
1728
# TODO: the pending list should be lexically sorted?
1729
current_root = search_specific_files.pop()
1730
searched_specific_files.add(current_root)
1731
# process the entries for this containing directory: the rest will be
1732
# found by their parents recursively.
1733
root_entries = _entries_for_path(current_root)
1734
root_abspath = self.target.abspath(current_root)
1736
root_stat = os.lstat(root_abspath)
1738
if e.errno == errno.ENOENT:
1739
# the path does not exist: let _process_entry know that.
1740
root_dir_info = None
1742
# some other random error: hand it up.
1745
root_dir_info = ('', current_root,
1746
osutils.file_kind_from_stat_mode(root_stat.st_mode), root_stat,
1748
if not root_entries and not root_dir_info:
1749
# this specified path is not present at all, skip it.
1751
for entry in root_entries:
1752
for result in _process_entry(entry, root_dir_info):
1753
# this check should probably be outside the loop: one
1754
# 'iterate two trees' api, and then _iter_changes filters
1755
# unchanged pairs. - RBC 20070226
1756
if (include_unchanged
1757
or result[2] # content change
1758
or result[3][0] != result[3][1] # versioned status
1759
or result[4][0] != result[4][1] # parent id
1760
or result[5][0] != result[5][1] # name
1761
or result[6][0] != result[6][1] # kind
1762
or result[7][0] != result[7][1] # executable
1765
dir_iterator = osutils._walkdirs_utf8(root_abspath, prefix=current_root)
1766
initial_key = (current_root, '', '')
1767
block_index, _ = state._find_block_index_from_key(initial_key)
1768
if block_index == 0:
1769
# we have processed the total root already, but because the
1770
# initial key matched it we should skip it here.
1773
current_dir_info = dir_iterator.next()
1775
if e.errno in (errno.ENOENT, errno.ENOTDIR):
1776
# there may be directories in the inventory even though
1777
# this path is not a file on disk: so mark it as end of
1779
current_dir_info = None
1783
if current_dir_info[0][0] == '':
1784
# remove .bzr from iteration
1785
bzr_index = bisect_left(current_dir_info[1], ('.bzr',))
1786
assert current_dir_info[1][bzr_index][0] == '.bzr'
1787
del current_dir_info[1][bzr_index]
1788
# walk until both the directory listing and the versioned metadata
1789
# are exhausted. TODO: reevaluate this, perhaps we should stop when
1790
# the versioned data runs out.
1791
if (block_index < len(state._dirblocks) and
1792
osutils.is_inside(current_root, state._dirblocks[block_index][0])):
1793
current_block = state._dirblocks[block_index]
1795
current_block = None
1796
while (current_dir_info is not None or
1797
current_block is not None):
1798
if (current_dir_info and current_block
1799
and current_dir_info[0][0] != current_block[0]):
1800
if current_dir_info[0][0] < current_block[0] :
1801
# import pdb; pdb.set_trace()
1802
# print 'unversioned dir'
1803
# filesystem data refers to paths not covered by the dirblock.
1804
# this has two possibilities:
1805
# A) it is versioned but empty, so there is no block for it
1806
# B) it is not versioned.
1807
# in either case it was processed by the containing directories walk:
1808
# if it is root/foo, when we walked root we emitted it,
1809
# or if we ere given root/foo to walk specifically, we
1810
# emitted it when checking the walk-root entries
1811
# advance the iterator and loop - we dont need to emit it.
1813
current_dir_info = dir_iterator.next()
1814
except StopIteration:
1815
current_dir_info = None
1817
# We have a dirblock entry for this location, but there
1818
# is no filesystem path for this. This is most likely
1819
# because a directory was removed from the disk.
1820
# We don't have to report the missing directory,
1821
# because that should have already been handled, but we
1822
# need to handle all of the files that are contained
1824
for current_entry in current_block[1]:
1825
# entry referring to file not present on disk.
1826
# advance the entry only, after processing.
1827
for result in _process_entry(current_entry, None):
1828
# this check should probably be outside the loop: one
1829
# 'iterate two trees' api, and then _iter_changes filters
1830
# unchanged pairs. - RBC 20070226
1831
if (include_unchanged
1832
or result[2] # content change
1833
or result[3][0] != result[3][1] # versioned status
1834
or result[4][0] != result[4][1] # parent id
1835
or result[5][0] != result[5][1] # name
1836
or result[6][0] != result[6][1] # kind
1837
or result[7][0] != result[7][1] # executable
1841
if (block_index < len(state._dirblocks) and
1842
osutils.is_inside(current_root,
1843
state._dirblocks[block_index][0])):
1844
current_block = state._dirblocks[block_index]
1846
current_block = None
1849
if current_block and entry_index < len(current_block[1]):
1850
current_entry = current_block[1][entry_index]
1852
current_entry = None
1853
advance_entry = True
1855
if current_dir_info and path_index < len(current_dir_info[1]):
1856
current_path_info = current_dir_info[1][path_index]
1858
current_path_info = None
1860
while (current_entry is not None or
1861
current_path_info is not None):
1862
if current_entry is None:
1863
# no more entries: yield current_pathinfo as an
1864
# unversioned file: its not the same as a path in any
1865
# tree in the dirstate.
1866
new_executable = bool(
1867
stat.S_ISREG(current_path_info[3].st_mode)
1868
and stat.S_IEXEC & current_path_info[3].st_mode)
1869
yield (None, current_path_info[0], True,
1872
(None, current_path_info[1]),
1873
(None, current_path_info[2]),
1874
(None, new_executable))
1875
elif current_path_info is None:
1876
# no path is fine: the per entry code will handle it.
1877
for result in _process_entry(current_entry, current_path_info):
1878
# this check should probably be outside the loop: one
1879
# 'iterate two trees' api, and then _iter_changes filters
1880
# unchanged pairs. - RBC 20070226
1881
if (include_unchanged
1882
or result[2] # content change
1883
or result[3][0] != result[3][1] # versioned status
1884
or result[4][0] != result[4][1] # parent id
1885
or result[5][0] != result[5][1] # name
1886
or result[6][0] != result[6][1] # kind
1887
or result[7][0] != result[7][1] # executable
1890
elif current_entry[0][1] != current_path_info[1]:
1891
if current_path_info[1] < current_entry[0][1]:
1892
# extra file on disk: pass for now, but only
1893
# increment the path, not the entry
1894
# import pdb; pdb.set_trace()
1895
# print 'unversioned file'
1896
advance_entry = False
1898
# entry referring to file not present on disk.
1899
# advance the entry only, after processing.
1900
for result in _process_entry(current_entry, None):
1901
# this check should probably be outside the loop: one
1902
# 'iterate two trees' api, and then _iter_changes filters
1903
# unchanged pairs. - RBC 20070226
1904
if (include_unchanged
1905
or result[2] # content change
1906
or result[3][0] != result[3][1] # versioned status
1907
or result[4][0] != result[4][1] # parent id
1908
or result[5][0] != result[5][1] # name
1909
or result[6][0] != result[6][1] # kind
1910
or result[7][0] != result[7][1] # executable
1913
advance_path = False
1915
for result in _process_entry(current_entry, current_path_info):
1916
# this check should probably be outside the loop: one
1917
# 'iterate two trees' api, and then _iter_changes filters
1918
# unchanged pairs. - RBC 20070226
1919
if (include_unchanged
1920
or result[2] # content change
1921
or result[3][0] != result[3][1] # versioned status
1922
or result[4][0] != result[4][1] # parent id
1923
or result[5][0] != result[5][1] # name
1924
or result[6][0] != result[6][1] # kind
1925
or result[7][0] != result[7][1] # executable
1928
if advance_entry and current_entry is not None:
1930
if entry_index < len(current_block[1]):
1931
current_entry = current_block[1][entry_index]
1933
current_entry = None
1935
advance_entry = True # reset the advance flaga
1936
if advance_path and current_path_info is not None:
1938
if path_index < len(current_dir_info[1]):
1939
current_path_info = current_dir_info[1][path_index]
1941
current_path_info = None
1943
advance_path = True # reset the advance flagg.
1944
if current_block is not None:
1946
if (block_index < len(state._dirblocks) and
1947
osutils.is_inside(current_root, state._dirblocks[block_index][0])):
1948
current_block = state._dirblocks[block_index]
1950
current_block = None
1951
if current_dir_info is not None:
1953
current_dir_info = dir_iterator.next()
1954
except StopIteration:
1955
current_dir_info = None
1984
use_filesystem_for_exec = (sys.platform != 'win32')
1985
iter_changes = self.target._iter_changes(include_unchanged,
1986
use_filesystem_for_exec, search_specific_files, state,
1987
source_index, target_index, want_unversioned, self.target)
1988
return iter_changes.iter_changes()
1959
1991
def is_compatible(source, target):
1960
1992
# the target must be a dirstate working tree
1961
if not isinstance(target, WorkingTree4):
1993
if not isinstance(target, DirStateWorkingTree):
1963
# the source must be a revtreee or dirstate rev tree.
1995
# the source must be a revtree or dirstate rev tree.
1964
1996
if not isinstance(source,
1965
1997
(revisiontree.RevisionTree, DirStateRevisionTree)):