13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""WorkingTree object and friends.
19
19
A WorkingTree represents the editable working copy of a branch.
20
Operations which represent the WorkingTree are also done here,
21
such as renaming or adding files. The WorkingTree has an inventory
22
which is updated by these operations. A commit produces a
20
Operations which represent the WorkingTree are also done here,
21
such as renaming or adding files. The WorkingTree has an inventory
22
which is updated by these operations. A commit produces a
23
23
new revision based on the workingtree and its inventory.
25
25
At the moment every WorkingTree has its own branch. Remote
57
59
conflicts as _mod_conflicts,
66
67
revision as _mod_revision,
75
79
import bzrlib.branch
76
80
from bzrlib.transport import get_transport
77
from bzrlib.workingtree_4 import (
82
from bzrlib.workingtree_4 import WorkingTreeFormat4, WorkingTreeFormat5
84
85
from bzrlib import symbol_versioning
85
86
from bzrlib.decorators import needs_read_lock, needs_write_lock
87
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
86
88
from bzrlib.lockable_files import LockableFiles
87
89
from bzrlib.lockdir import LockDir
88
90
import bzrlib.mutabletree
89
91
from bzrlib.mutabletree import needs_tree_write_lock
90
92
from bzrlib import osutils
91
93
from bzrlib.osutils import (
99
103
supports_executable,
101
from bzrlib.filters import filtered_input_file
102
105
from bzrlib.trace import mutter, note
103
106
from bzrlib.transport.local import LocalTransport
104
107
from bzrlib.progress import DummyProgress, ProgressPhase
105
from bzrlib.revision import CURRENT_REVISION
108
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
106
109
from bzrlib.rio import RioReader, rio_file, Stanza
107
from bzrlib.symbol_versioning import (
109
DEPRECATED_PARAMETER,
110
from bzrlib.symbol_versioning import (deprecated_passed,
113
DEPRECATED_PARAMETER,
113
117
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
119
123
class TreeEntry(object):
120
124
"""An entry that implements the minimum interface used by commands.
122
This needs further inspection, it may be better to have
126
This needs further inspection, it may be better to have
123
127
InventoryEntries without ids - though that seems wrong. For now,
124
128
this is a parallel hierarchy to InventoryEntry, and needs to become
125
129
one of several things: decorates to that hierarchy, children of, or
128
132
no InventoryEntry available - i.e. for unversioned objects.
129
133
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
132
136
def __eq__(self, other):
133
137
# yes, this us ugly, TODO: best practice __eq__ style.
134
138
return (isinstance(other, TreeEntry)
135
139
and other.__class__ == self.__class__)
137
141
def kind_character(self):
225
225
wt_trans = self.bzrdir.get_workingtree_transport(None)
226
226
cache_filename = wt_trans.local_abspath('stat-cache')
227
227
self._hashcache = hashcache.HashCache(basedir, cache_filename,
228
self.bzrdir._get_file_mode(),
229
self._content_filter_stack_provider())
228
self.bzrdir._get_file_mode())
230
229
hc = self._hashcache
232
231
# is this scan needed ? it makes things kinda slow.
280
278
self._control_files.break_lock()
281
279
self.branch.break_lock()
283
def _get_check_refs(self):
284
"""Return the references needed to perform a check of this tree.
286
The default implementation returns no refs, and is only suitable for
287
trees that have no local caching and can commit on ghosts at any time.
289
:seealso: bzrlib.check for details about check_refs.
293
281
def requires_rich_root(self):
294
282
return self._format.requires_rich_root
300
288
return self._format.supports_content_filtering()
302
290
def supports_views(self):
303
return self.views.supports_views()
291
return self._format.supports_views()
305
293
def _set_inventory(self, inv, dirty):
306
294
"""Set the internal cached inventory.
419
407
return self.branch.repository.revision_tree(revision_id)
420
408
except (errors.RevisionNotPresent, errors.NoSuchRevision):
421
409
# the basis tree *may* be a ghost or a low level error may have
422
# occurred. If the revision is present, its a problem, if its not
410
# occured. If the revision is present, its a problem, if its not
424
412
if self.branch.repository.has_revision(revision_id):
441
429
def has_filename(self, filename):
442
430
return osutils.lexists(self.abspath(filename))
444
def get_file(self, file_id, path=None, filtered=True):
445
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
432
def get_file(self, file_id, path=None):
433
return self.get_file_with_stat(file_id, path)[0]
447
def get_file_with_stat(self, file_id, path=None, filtered=True,
449
"""See Tree.get_file_with_stat."""
435
def get_file_with_stat(self, file_id, path=None, _fstat=os.fstat):
436
"""See MutableTree.get_file_with_stat."""
451
438
path = self.id2path(file_id)
452
file_obj = self.get_file_byname(path, filtered=False)
453
stat_value = _fstat(file_obj.fileno())
454
if filtered and self.supports_content_filtering():
455
filters = self._content_filter_stack(path)
456
file_obj = filtered_input_file(file_obj, filters)
457
return (file_obj, stat_value)
459
def get_file_text(self, file_id, path=None, filtered=True):
460
return self.get_file(file_id, path=path, filtered=filtered).read()
462
def get_file_byname(self, filename, filtered=True):
463
path = self.abspath(filename)
465
if filtered and self.supports_content_filtering():
466
filters = self._content_filter_stack(filename)
467
return filtered_input_file(f, filters)
471
def get_file_lines(self, file_id, path=None, filtered=True):
439
file_obj = self.get_file_byname(path)
440
return (file_obj, _fstat(file_obj.fileno()))
442
def get_file_byname(self, filename):
443
return file(self.abspath(filename), 'rb')
445
def get_file_lines(self, file_id, path=None):
472
446
"""See Tree.get_file_lines()"""
473
file = self.get_file(file_id, path, filtered=filtered)
447
file = self.get_file(file_id, path)
475
449
return file.readlines()
487
461
incorrectly attributed to CURRENT_REVISION (but after committing, the
488
462
attribution will be correct).
490
maybe_file_parent_keys = []
491
for parent_id in self.get_parent_ids():
493
parent_tree = self.revision_tree(parent_id)
494
except errors.NoSuchRevisionInTree:
495
parent_tree = self.branch.repository.revision_tree(parent_id)
496
parent_tree.lock_read()
498
if file_id not in parent_tree:
500
ie = parent_tree.inventory[file_id]
501
if ie.kind != 'file':
502
# Note: this is slightly unnecessary, because symlinks and
503
# directories have a "text" which is the empty text, and we
504
# know that won't mess up annotations. But it seems cleaner
506
parent_text_key = (file_id, ie.revision)
507
if parent_text_key not in maybe_file_parent_keys:
508
maybe_file_parent_keys.append(parent_text_key)
511
graph = _mod_graph.Graph(self.branch.repository.texts)
512
heads = graph.heads(maybe_file_parent_keys)
513
file_parent_keys = []
514
for key in maybe_file_parent_keys:
516
file_parent_keys.append(key)
518
# Now we have the parents of this content
519
annotator = self.branch.repository.texts.get_annotator()
520
text = self.get_file(file_id).read()
521
this_key =(file_id, default_revision)
522
annotator.add_special_text(this_key, file_parent_keys, text)
523
annotations = [(key[-1], line)
524
for key, line in annotator.annotate_flat(this_key)]
464
basis = self.basis_tree()
467
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
468
require_versioned=True).next()
469
changed_content, kind = changes[2], changes[6]
470
if not changed_content:
471
return basis.annotate_iter(file_id)
475
if kind[0] != 'file':
478
old_lines = list(basis.annotate_iter(file_id))
480
for tree in self.branch.repository.revision_trees(
481
self.get_parent_ids()[1:]):
482
if file_id not in tree:
484
old.append(list(tree.annotate_iter(file_id)))
485
return annotate.reannotate(old, self.get_file(file_id).readlines(),
527
490
def _get_ancestors(self, default_revision):
528
491
ancestors = set([default_revision])
544
507
parents = [last_rev]
546
merges_bytes = self._transport.get_bytes('pending-merges')
509
merges_file = self._transport.get('pending-merges')
547
510
except errors.NoSuchFile:
550
for l in osutils.split_lines(merges_bytes):
513
for l in merges_file.readlines():
551
514
revision_id = l.rstrip('\n')
552
515
parents.append(revision_id)
565
528
def clone(self, to_bzrdir, revision_id=None):
566
529
"""Duplicate this working tree into to_bzr, including all state.
568
531
Specifically modified files are kept as modified, but
569
532
ignored and unknown files are discarded.
571
534
If you want to make a new line of development, see bzrdir.sprout()
574
If not None, the cloned tree will have its last revision set to
575
revision, and difference between the source trees last revision
537
If not None, the cloned tree will have its last revision set to
538
revision, and and difference between the source trees last revision
576
539
and this one merged in.
578
541
# assumes the target bzr dir format is compatible.
636
597
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
637
598
file_id = self.path2id(path)
639
# For unversioned files on win32, we just assume they are not
642
599
return self._inventory[file_id].executable
644
601
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
666
623
"""See MutableTree._add."""
667
624
# TODO: Re-adding a file that is removed in the working copy
668
625
# should probably put it back with the previous ID.
669
# the read and write working inventory should not occur in this
626
# the read and write working inventory should not occur in this
670
627
# function - they should be part of lock_write and unlock.
671
628
inv = self.inventory
672
629
for f, file_id, kind in zip(files, ids, kinds):
755
712
kind = _mapper(stat_result.st_mode)
756
713
if kind == 'file':
757
return self._file_content_summary(path, stat_result)
714
size = stat_result.st_size
715
# try for a stat cache lookup
716
executable = self._is_executable_from_path_and_stat(path, stat_result)
717
return (kind, size, executable, self._sha_from_stat(
758
719
elif kind == 'directory':
759
720
# perhaps it looks like a plain directory, but it's really a
762
723
kind = 'tree-reference'
763
724
return kind, None, None, None
764
725
elif kind == 'symlink':
765
target = osutils.readlink(abspath)
766
return ('symlink', None, None, target)
726
return ('symlink', None, None, os.readlink(abspath))
768
728
return (kind, None, None, None)
770
def _file_content_summary(self, path, stat_result):
771
size = stat_result.st_size
772
executable = self._is_executable_from_path_and_stat(path, stat_result)
773
# try for a stat cache lookup
774
return ('file', size, executable, self._sha_from_stat(
777
730
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
778
731
"""Common ghost checking functionality from set_parent_*.
789
742
def _set_merges_from_parent_ids(self, parent_ids):
790
743
merges = parent_ids[1:]
791
744
self._transport.put_bytes('pending-merges', '\n'.join(merges),
792
mode=self.bzrdir._get_file_mode())
745
mode=self._control_files._file_mode)
794
747
def _filter_parent_ids_by_ancestry(self, revision_ids):
795
748
"""Check that all merged revisions are proper 'heads'.
797
750
This will always return the first revision_id, and any merged revisions
800
753
if len(revision_ids) == 0:
801
754
return revision_ids
813
766
@needs_tree_write_lock
814
767
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
815
768
"""Set the parent ids to revision_ids.
817
770
See also set_parent_trees. This api will try to retrieve the tree data
818
771
for each element of revision_ids from the trees repository. If you have
819
772
tree data already available, it is more efficient to use
895
848
self._must_be_locked()
896
849
my_file = rio_file(stanzas, header)
897
850
self._transport.put_file(filename, my_file,
898
mode=self.bzrdir._get_file_mode())
851
mode=self._control_files._file_mode)
900
853
@needs_write_lock # because merge pulls data into the branch.
901
854
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
902
merge_type=None, force=False):
903
856
"""Merge from a branch into this working tree.
905
858
:param branch: The branch to merge from.
909
862
branch.last_revision().
911
864
from bzrlib.merge import Merger, Merge3Merger
912
pb = ui.ui_factory.nested_progress_bar()
865
pb = bzrlib.ui.ui_factory.nested_progress_bar()
914
867
merger = Merger(self.branch, this_tree=self, pb=pb)
915
868
merger.pp = ProgressPhase("Merge phase", 5, pb)
916
869
merger.pp.next_phase()
917
# check that there are no local alterations
918
if not force and self.has_changes():
919
raise errors.UncommittedChanges(self)
870
# check that there are no
872
merger.check_basis(check_clean=True, require_commits=False)
920
873
if to_revision is None:
921
874
to_revision = _mod_revision.ensure_null(branch.last_revision())
922
875
merger.other_rev_id = to_revision
1052
1003
def _directory_may_be_tree_reference(self, relpath):
1053
# as a special case, if a directory contains control files then
1004
# as a special case, if a directory contains control files then
1054
1005
# it's a tree reference, except that the root of the tree is not
1055
1006
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1056
1007
# TODO: We could ask all the control formats whether they
1101
1052
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1103
1054
tree_bzrdir = branch_bzrdir
1104
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1055
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1105
1056
wt.set_parent_ids(self.get_parent_ids())
1106
1057
my_inv = self.inventory
1107
child_inv = inventory.Inventory(root_id=None)
1058
child_inv = Inventory(root_id=None)
1108
1059
new_root = my_inv[file_id]
1109
1060
my_inv.remove_recursive_id(file_id)
1110
1061
new_root.parent_id = None
1129
1080
self._serialize(self._inventory, sio)
1131
1082
self._transport.put_file('inventory', sio,
1132
mode=self.bzrdir._get_file_mode())
1083
mode=self._control_files._file_mode)
1133
1084
self._inventory_is_modified = False
1135
1086
def _kind(self, relpath):
1136
1087
return osutils.file_kind(self.abspath(relpath))
1138
def list_files(self, include_root=False, from_dir=None, recursive=True):
1139
"""List all files as (path, class, kind, id, entry).
1089
def list_files(self, include_root=False):
1090
"""Recursively list all files as (path, class, kind, id, entry).
1141
1092
Lists, but does not descend into unversioned directories.
1142
1094
This does not include files that have been deleted in this
1143
tree. Skips the control directory.
1145
:param include_root: if True, do not return an entry for the root
1146
:param from_dir: start from this directory or None for the root
1147
:param recursive: whether to recurse into subdirectories or not
1097
Skips the control directory.
1149
1099
# list_files is an iterator, so @needs_read_lock doesn't work properly
1150
1100
# with it. So callers should be careful to always read_lock the tree.
1152
1102
raise errors.ObjectNotLocked(self)
1154
1104
inv = self.inventory
1155
if from_dir is None and include_root is True:
1105
if include_root is True:
1156
1106
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1157
1107
# Convert these into local objects to save lookup times
1158
1108
pathjoin = osutils.pathjoin
1165
1115
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1167
1117
# directory file_id, relative path, absolute path, reverse sorted children
1168
if from_dir is not None:
1169
from_dir_id = inv.path2id(from_dir)
1170
if from_dir_id is None:
1171
# Directory not versioned
1173
from_dir_abspath = pathjoin(self.basedir, from_dir)
1175
from_dir_id = inv.root.file_id
1176
from_dir_abspath = self.basedir
1177
children = os.listdir(from_dir_abspath)
1118
children = os.listdir(self.basedir)
1178
1119
children.sort()
1179
# jam 20060527 The kernel sized tree seems equivalent whether we
1120
# jam 20060527 The kernel sized tree seems equivalent whether we
1180
1121
# use a deque and popleft to keep them sorted, or if we use a plain
1181
1122
# list and just reverse() them.
1182
1123
children = collections.deque(children)
1183
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1124
stack = [(inv.root.file_id, u'', self.basedir, children)]
1185
1126
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1240
1181
except KeyError:
1241
1182
yield fp[1:], c, fk, None, TreeEntry()
1244
1185
if fk != 'directory':
1247
# But do this child first if recursing down
1249
new_children = os.listdir(fap)
1251
new_children = collections.deque(new_children)
1252
stack.append((f_ie.file_id, fp, fap, new_children))
1253
# Break out of inner loop,
1254
# so that we start outer loop with child
1188
# But do this child first
1189
new_children = os.listdir(fap)
1191
new_children = collections.deque(new_children)
1192
stack.append((f_ie.file_id, fp, fap, new_children))
1193
# Break out of inner loop,
1194
# so that we start outer loop with child
1257
1197
# if we finished all children, pop it off the stack
1264
1204
to_dir must exist in the inventory.
1266
1206
If to_dir exists and is a directory, the files are moved into
1267
it, keeping their old names.
1207
it, keeping their old names.
1269
1209
Note that to_dir is only the last component of the new name;
1270
1210
this doesn't change the directory.
1436
1376
inv = self.inventory
1437
1377
for entry in moved:
1439
self._move_entry(WorkingTree._RenameEntry(
1440
entry.to_rel, entry.from_id,
1379
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1441
1380
entry.to_tail, entry.to_parent_id, entry.from_rel,
1442
1381
entry.from_tail, entry.from_parent_id,
1443
1382
entry.only_change_inv))
1494
1433
from_tail = splitpath(from_rel)[-1]
1495
1434
from_id = inv.path2id(from_rel)
1496
1435
if from_id is None:
1497
# if file is missing in the inventory maybe it's in the basis_tree
1498
basis_tree = self.branch.basis_tree()
1499
from_id = basis_tree.path2id(from_rel)
1501
raise errors.BzrRenameFailedError(from_rel,to_rel,
1502
errors.NotVersionedError(path=str(from_rel)))
1503
# put entry back in the inventory so we can rename it
1504
from_entry = basis_tree.inventory[from_id].copy()
1507
from_entry = inv[from_id]
1436
raise errors.BzrRenameFailedError(from_rel,to_rel,
1437
errors.NotVersionedError(path=str(from_rel)))
1438
from_entry = inv[from_id]
1508
1439
from_parent_id = from_entry.parent_id
1509
1440
to_dir, to_tail = os.path.split(to_rel)
1510
1441
to_dir_id = inv.path2id(to_dir)
1556
1487
These are files in the working directory that are not versioned or
1557
1488
control files or ignored.
1559
# force the extras method to be fully executed before returning, to
1490
# force the extras method to be fully executed before returning, to
1560
1491
# prevent race conditions with the lock
1562
1493
[subp for subp in self.extras() if not self.is_ignored(subp)])
1572
1503
:raises: NoSuchId if any fileid is not currently versioned.
1574
1505
for file_id in file_ids:
1575
if file_id not in self._inventory:
1576
raise errors.NoSuchId(self, file_id)
1577
for file_id in file_ids:
1578
1506
if self._inventory.has_id(file_id):
1579
1507
self._inventory.remove_recursive_id(file_id)
1509
raise errors.NoSuchId(self, file_id)
1580
1510
if len(file_ids):
1581
# in the future this should just set a dirty bit to wait for the
1511
# in the future this should just set a dirty bit to wait for the
1582
1512
# final unlock. However, until all methods of workingtree start
1583
# with the current in -memory inventory rather than triggering
1513
# with the current in -memory inventory rather than triggering
1584
1514
# a read, it is more complex - we need to teach read_inventory
1585
1515
# to know when to read, and when to not read first... and possibly
1586
1516
# to save first when the in memory one may be corrupted.
1587
1517
# so for now, we just only write it if it is indeed dirty.
1588
1518
# - RBC 20060907
1589
1519
self._write_inventory(self._inventory)
1591
1521
def _iter_conflicts(self):
1592
1522
conflicted = set()
1593
1523
for info in self.list_files():
1602
1532
@needs_write_lock
1603
1533
def pull(self, source, overwrite=False, stop_revision=None,
1604
change_reporter=None, possible_transports=None, local=False):
1605
top_pb = ui.ui_factory.nested_progress_bar()
1534
change_reporter=None, possible_transports=None):
1535
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1606
1536
source.lock_read()
1608
1538
pp = ProgressPhase("Pull phase", 2, top_pb)
1610
1540
old_revision_info = self.branch.last_revision_info()
1611
1541
basis_tree = self.basis_tree()
1612
1542
count = self.branch.pull(source, overwrite, stop_revision,
1613
possible_transports=possible_transports,
1543
possible_transports=possible_transports)
1615
1544
new_revision_info = self.branch.last_revision_info()
1616
1545
if new_revision_info != old_revision_info:
1617
1546
pp.next_phase()
1618
1547
repository = self.branch.repository
1619
pb = ui.ui_factory.nested_progress_bar()
1548
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1620
1549
basis_tree.lock_read()
1622
1551
new_basis_tree = self.branch.basis_tree()
1627
1556
this_tree=self,
1629
1558
change_reporter=change_reporter)
1630
basis_root_id = basis_tree.get_root_id()
1631
new_root_id = new_basis_tree.get_root_id()
1632
if basis_root_id != new_root_id:
1633
self.set_root_id(new_root_id)
1559
if (basis_tree.inventory.root is None and
1560
new_basis_tree.inventory.root is not None):
1561
self.set_root_id(new_basis_tree.get_root_id())
1636
1564
basis_tree.unlock()
1638
1566
# reuse the revisiontree we merged against to set the new
1640
1568
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1641
# we have to pull the merge trees out again, because
1642
# merge_inner has set the ids. - this corner is not yet
1569
# we have to pull the merge trees out again, because
1570
# merge_inner has set the ids. - this corner is not yet
1643
1571
# layered well enough to prevent double handling.
1644
1572
# XXX TODO: Fix the double handling: telling the tree about
1645
1573
# the already known parent data is wasteful.
1879
1803
path = self._basis_inventory_name()
1880
1804
sio = StringIO(xml)
1881
1805
self._transport.put_file(path, sio,
1882
mode=self.bzrdir._get_file_mode())
1806
mode=self._control_files._file_mode)
1884
1808
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1885
1809
"""Create the text that will be saved in basis-inventory"""
1892
1816
# as commit already has that ready-to-use [while the format is the
1893
1817
# same, that is].
1895
# this double handles the inventory - unpack and repack -
1819
# this double handles the inventory - unpack and repack -
1896
1820
# but is easier to understand. We can/should put a conditional
1897
1821
# in here based on whether the inventory is in the latest format
1898
1822
# - perhaps we should repack all inventories on a repository
1900
1824
# the fast path is to copy the raw xml from the repository. If the
1901
# xml contains 'revision_id="', then we assume the right
1825
# xml contains 'revision_id="', then we assume the right
1902
1826
# revision_id is set. We must check for this full string, because a
1903
1827
# root node id can legitimately look like 'revision_id' but cannot
1904
1828
# contain a '"'.
1905
1829
xml = self.branch.repository.get_inventory_xml(new_revision)
1906
1830
firstline = xml.split('\n', 1)[0]
1907
if (not 'revision_id="' in firstline or
1831
if (not 'revision_id="' in firstline or
1908
1832
'format="7"' not in firstline):
1909
inv = self.branch.repository._serializer.read_inventory_from_string(
1833
inv = self.branch.repository.deserialise_inventory(
1911
1835
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1912
1836
self._write_basis_inventory(xml)
1913
1837
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1917
1841
"""Read the cached basis inventory."""
1918
1842
path = self._basis_inventory_name()
1919
1843
return self._transport.get_bytes(path)
1921
1845
@needs_read_lock
1922
1846
def read_working_inventory(self):
1923
1847
"""Read the working inventory.
1925
1849
:raises errors.InventoryModified: read_working_inventory will fail
1926
1850
when the current in memory inventory has been modified.
1928
# conceptually this should be an implementation detail of the tree.
1852
# conceptually this should be an implementation detail of the tree.
1929
1853
# XXX: Deprecate this.
1930
1854
# ElementTree does its own conversion from UTF-8, so open in
1932
1856
if self._inventory_is_modified:
1933
1857
raise errors.InventoryModified(self)
1934
f = self._transport.get('inventory')
1936
result = self._deserialize(f)
1858
result = self._deserialize(self._transport.get('inventory'))
1939
1859
self._set_inventory(result, dirty=False)
2033
1951
new_status = 'I'
2035
1953
new_status = '?'
2036
# XXX: Really should be a more abstract reporter interface
2037
kind_ch = osutils.kind_marker(self.kind(fid))
2038
to_file.write(new_status + ' ' + f + kind_ch + '\n')
1954
textui.show_status(new_status, self.kind(fid), f,
2039
1956
# Unversion file
2040
1957
inv_delta.append((f, None, fid, None))
2041
1958
message = "removed %s" % (f,)
2134
2052
name = os.path.basename(path)
2137
# fixme, there should be a factory function inv,add_??
2055
# fixme, there should be a factory function inv,add_??
2138
2056
if kind == 'directory':
2139
2057
inv.add(InventoryDirectory(file_id, name, parent))
2140
2058
elif kind == 'file':
2158
2076
def _set_root_id(self, file_id):
2159
2077
"""Set the root id for this tree, in a format specific manner.
2161
:param file_id: The file id to assign to the root. It must not be
2079
:param file_id: The file id to assign to the root. It must not be
2162
2080
present in the current inventory or an error will occur. It must
2163
2081
not be None, but rather a valid file id.
2184
2102
def unlock(self):
2185
2103
"""See Branch.unlock.
2187
2105
WorkingTree locking just uses the Branch locking facilities.
2188
2106
This is current because all working trees have an embedded branch
2189
2107
within them. IF in the future, we were to make branch data shareable
2190
between multiple working trees, i.e. via shared storage, then we
2108
between multiple working trees, i.e. via shared storage, then we
2191
2109
would probably want to lock both the local tree, and the branch.
2193
2111
raise NotImplementedError(self.unlock)
2197
def update(self, change_reporter=None, possible_transports=None,
2198
revision=None, old_tip=_marker):
2113
def update(self, change_reporter=None, possible_transports=None):
2199
2114
"""Update a working tree along its branch.
2201
2116
This will update the branch if its bound too, which means we have
2219
2134
- Merge current state -> basis tree of the master w.r.t. the old tree
2221
2136
- Do a 'normal' merge of the old branch basis if it is relevant.
2223
:param revision: The target revision to update to. Must be in the
2225
:param old_tip: If branch.update() has already been run, the value it
2226
returned (old tip of the branch or None). _marker is used
2229
2138
if self.branch.get_bound_location() is not None:
2230
2139
self.lock_write()
2231
update_branch = (old_tip is self._marker)
2140
update_branch = True
2233
2142
self.lock_tree_write()
2234
2143
update_branch = False
2236
2145
if update_branch:
2237
2146
old_tip = self.branch.update(possible_transports)
2239
if old_tip is self._marker:
2241
return self._update_tree(old_tip, change_reporter, revision)
2149
return self._update_tree(old_tip, change_reporter)
2245
2153
@needs_tree_write_lock
2246
def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2154
def _update_tree(self, old_tip=None, change_reporter=None):
2247
2155
"""Update a tree to the master branch.
2249
2157
:param old_tip: if supplied, the previous tip revision the branch,
2255
2163
# cant set that until we update the working trees last revision to be
2256
2164
# one from the new branch, because it will just get absorbed by the
2257
2165
# parent de-duplication logic.
2259
2167
# We MUST save it even if an error occurs, because otherwise the users
2260
2168
# local work is unreferenced and will appear to have been lost.
2264
2172
last_rev = self.get_parent_ids()[0]
2265
2173
except IndexError:
2266
2174
last_rev = _mod_revision.NULL_REVISION
2267
if revision is None:
2268
revision = self.branch.last_revision()
2270
if revision not in self.branch.revision_history():
2271
raise errors.NoSuchRevision(self.branch, revision)
2272
if last_rev != _mod_revision.ensure_null(revision):
2273
# merge tree state up to specified revision.
2175
if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2176
# merge tree state up to new branch tip.
2274
2177
basis = self.basis_tree()
2275
2178
basis.lock_read()
2277
to_tree = self.branch.repository.revision_tree(revision)
2278
to_root_id = to_tree.get_root_id()
2279
if (basis.inventory.root is None
2280
or basis.inventory.root.file_id != to_root_id):
2281
self.set_root_id(to_root_id)
2180
to_tree = self.branch.basis_tree()
2181
if basis.inventory.root is None:
2182
self.set_root_id(to_tree.get_root_id())
2283
2184
result += merge.merge_inner(
2287
2188
this_tree=self,
2288
2189
change_reporter=change_reporter)
2289
self.set_last_revision(revision)
2292
2192
# TODO - dedup parents list with things merged by pull ?
2293
2193
# reuse the tree we've updated to to set the basis:
2294
parent_trees = [(revision, to_tree)]
2194
parent_trees = [(self.branch.last_revision(), to_tree)]
2295
2195
merges = self.get_parent_ids()[1:]
2296
2196
# Ideally we ask the tree for the trees here, that way the working
2297
# tree can decide whether to give us the entire tree or give us a
2197
# tree can decide whether to give us teh entire tree or give us a
2298
2198
# lazy initialised tree. dirstate for instance will have the trees
2299
2199
# in ram already, whereas a last-revision + basis-inventory tree
2300
2200
# will not, but also does not need them when setting parents.
2327
2227
# should be able to remove this extra flush.
2329
2229
graph = self.branch.repository.get_graph()
2330
base_rev_id = graph.find_unique_lca(revision, old_tip)
2230
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2331
2232
base_tree = self.branch.repository.revision_tree(base_rev_id)
2332
2233
other_tree = self.branch.repository.revision_tree(old_tip)
2333
2234
result += merge.merge_inner(
2442
2343
bzrdir_loc = bisect_left(cur_disk_dir_content,
2443
2344
('.bzr', '.bzr'))
2444
2345
if (bzrdir_loc < len(cur_disk_dir_content)
2445
and self.bzrdir.is_control_filename(
2446
cur_disk_dir_content[bzrdir_loc][0])):
2346
and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2447
2347
# we dont yield the contents of, or, .bzr itself.
2448
2348
del cur_disk_dir_content[bzrdir_loc]
2449
2349
if inv_finished:
2583
2483
return un_resolved, resolved
2585
2485
@needs_read_lock
2586
def _check(self, references):
2587
"""Check the tree for consistency.
2589
:param references: A dict with keys matching the items returned by
2590
self._get_check_refs(), and values from looking those keys up in
2593
2487
tree_basis = self.basis_tree()
2594
2488
tree_basis.lock_read()
2596
repo_basis = references[('trees', self.last_revision())]
2490
repo_basis = self.branch.repository.revision_tree(
2491
self.last_revision())
2597
2492
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2598
2493
raise errors.BzrCheckError(
2599
2494
"Mismatched basis inventory content.")
2644
2540
if self._inventory is None:
2645
2541
self.read_working_inventory()
2647
def _get_check_refs(self):
2648
"""Return the references needed to perform a check of this tree."""
2649
return [('trees', self.last_revision())]
2651
2543
def lock_tree_write(self):
2652
2544
"""See WorkingTree.lock_tree_write().
2709
2601
self._transport.put_bytes('last-revision', revision_id,
2710
mode=self.bzrdir._get_file_mode())
2602
mode=self._control_files._file_mode)
2713
def _get_check_refs(self):
2714
"""Return the references needed to perform a check of this tree."""
2715
return [('trees', self.last_revision())]
2717
2605
@needs_tree_write_lock
2718
2606
def set_conflicts(self, conflicts):
2719
self._put_rio('conflicts', conflicts.to_stanzas(),
2607
self._put_rio('conflicts', conflicts.to_stanzas(),
2720
2608
CONFLICT_HEADER_1)
2722
2610
@needs_tree_write_lock
2771
2659
* a format string,
2772
2660
* an open routine.
2774
Formats are placed in an dict by their format string for reference
2662
Formats are placed in an dict by their format string for reference
2775
2663
during workingtree opening. Its not required that these be instances, they
2776
can be classes themselves with class methods - it simply depends on
2664
can be classes themselves with class methods - it simply depends on
2777
2665
whether state is needed for a given format or not.
2779
2667
Once a format is deprecated, just deprecate the initialize and open
2780
methods on the format class. Do not deprecate the object, as the
2668
methods on the format class. Do not deprecate the object, as the
2781
2669
object will be created every time regardless.
2796
2684
"""Return the format for the working tree object in a_bzrdir."""
2798
2686
transport = a_bzrdir.get_workingtree_transport(None)
2799
format_string = transport.get_bytes("format")
2687
format_string = transport.get("format").read()
2800
2688
return klass._formats[format_string]
2801
2689
except errors.NoSuchFile:
2802
2690
raise errors.NoWorkingTree(base=transport.base)
2970
2858
def _open_control_files(self, a_bzrdir):
2971
2859
transport = a_bzrdir.get_workingtree_transport(None)
2972
return LockableFiles(transport, self._lock_file_name,
2860
return LockableFiles(transport, self._lock_file_name,
2973
2861
self._lock_class)
2975
2863
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2976
2864
accelerator_tree=None, hardlink=False):
2977
2865
"""See WorkingTreeFormat.initialize().
2979
2867
:param revision_id: if supplied, create a working tree at a different
2980
2868
revision than the branch is at.
2981
2869
:param accelerator_tree: A tree which can be used for retrieving file
2992
2880
control_files.create_lock()
2993
2881
control_files.lock_write()
2994
2882
transport.put_bytes('format', self.get_format_string(),
2995
mode=a_bzrdir._get_file_mode())
2883
mode=control_files._file_mode)
2996
2884
if from_branch is not None:
2997
2885
branch = from_branch
3066
2954
return self.get_format_string()
3069
__default_format = WorkingTreeFormat6()
2957
__default_format = WorkingTreeFormat4()
3070
2958
WorkingTreeFormat.register_format(__default_format)
3071
2959
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3072
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3073
2960
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3074
2961
WorkingTreeFormat.set_default_format(__default_format)
3075
2962
# formats which have no format string are not discoverable