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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
59
57
conflicts as _mod_conflicts,
67
66
revision as _mod_revision,
79
76
import bzrlib.branch
80
77
from bzrlib.transport import get_transport
82
from bzrlib.workingtree_4 import WorkingTreeFormat4
78
from bzrlib.workingtree_4 import (
85
85
from bzrlib import symbol_versioning
86
86
from bzrlib.decorators import needs_read_lock, needs_write_lock
87
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
88
from bzrlib.lockable_files import LockableFiles, TransportLock
87
from bzrlib.lockable_files import LockableFiles
89
88
from bzrlib.lockdir import LockDir
90
89
import bzrlib.mutabletree
91
90
from bzrlib.mutabletree import needs_tree_write_lock
92
91
from bzrlib import osutils
93
92
from bzrlib.osutils import (
103
100
supports_executable,
102
from bzrlib.filters import filtered_input_file
105
103
from bzrlib.trace import mutter, note
106
104
from bzrlib.transport.local import LocalTransport
107
105
from bzrlib.progress import DummyProgress, ProgressPhase
108
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
106
from bzrlib.revision import CURRENT_REVISION
109
107
from bzrlib.rio import RioReader, rio_file, Stanza
110
from bzrlib.symbol_versioning import (deprecated_passed,
113
DEPRECATED_PARAMETER,
108
from bzrlib.symbol_versioning import (
110
DEPRECATED_PARAMETER,
117
114
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
123
120
class TreeEntry(object):
124
121
"""An entry that implements the minimum interface used by commands.
126
This needs further inspection, it may be better to have
123
This needs further inspection, it may be better to have
127
124
InventoryEntries without ids - though that seems wrong. For now,
128
125
this is a parallel hierarchy to InventoryEntry, and needs to become
129
126
one of several things: decorates to that hierarchy, children of, or
132
129
no InventoryEntry available - i.e. for unversioned objects.
133
130
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
136
133
def __eq__(self, other):
137
134
# yes, this us ugly, TODO: best practice __eq__ style.
138
135
return (isinstance(other, TreeEntry)
139
136
and other.__class__ == self.__class__)
141
138
def kind_character(self):
185
182
not listed in the Inventory and vice versa.
185
# override this to set the strategy for storing views
186
def _make_views(self):
187
return views.DisabledViews(self)
188
189
def __init__(self, basedir='.',
189
190
branch=DEPRECATED_PARAMETER,
225
226
wt_trans = self.bzrdir.get_workingtree_transport(None)
226
227
cache_filename = wt_trans.local_abspath('stat-cache')
227
228
self._hashcache = hashcache.HashCache(basedir, cache_filename,
228
self.bzrdir._get_file_mode())
229
self.bzrdir._get_file_mode(),
230
self._content_filter_stack_provider())
229
231
hc = self._hashcache
231
233
# is this scan needed ? it makes things kinda slow.
247
249
self._set_inventory(_inventory, dirty=False)
248
250
self._detect_case_handling()
249
251
self._rules_searcher = None
252
self.views = self._make_views()
251
254
def _detect_case_handling(self):
252
255
wt_trans = self.bzrdir.get_workingtree_transport(None)
278
281
self._control_files.break_lock()
279
282
self.branch.break_lock()
284
def _get_check_refs(self):
285
"""Return the references needed to perform a check of this tree.
287
The default implementation returns no refs, and is only suitable for
288
trees that have no local caching and can commit on ghosts at any time.
290
:seealso: bzrlib.check for details about check_refs.
281
294
def requires_rich_root(self):
282
295
return self._format.requires_rich_root
284
297
def supports_tree_reference(self):
300
def supports_content_filtering(self):
301
return self._format.supports_content_filtering()
303
def supports_views(self):
304
return self.views.supports_views()
287
306
def _set_inventory(self, inv, dirty):
288
307
"""Set the internal cached inventory.
306
path = os.path.getcwdu()
325
path = osutils.getcwd()
307
326
control = bzrdir.BzrDir.open(path, _unsupported)
308
327
return control.open_workingtree(_unsupported)
311
330
def open_containing(path=None):
312
331
"""Open an existing working tree which has its root about path.
314
333
This probes for a working tree at path and searches upwards from there.
316
335
Basically we keep looking up until we find the control directory or
378
397
def basis_tree(self):
379
398
"""Return RevisionTree for the current last revision.
381
400
If the left most parent is a ghost then the returned tree will be an
382
empty tree - one obtained by calling repository.revision_tree(None).
401
empty tree - one obtained by calling
402
repository.revision_tree(NULL_REVISION).
385
405
revision_id = self.get_parent_ids()[0]
387
407
# no parents, return an empty revision tree.
388
408
# in the future this should return the tree for
389
409
# 'empty:' - the implicit root empty tree.
390
return self.branch.repository.revision_tree(None)
410
return self.branch.repository.revision_tree(
411
_mod_revision.NULL_REVISION)
392
413
return self.revision_tree(revision_id)
393
414
except errors.NoSuchRevision:
399
420
return self.branch.repository.revision_tree(revision_id)
400
421
except (errors.RevisionNotPresent, errors.NoSuchRevision):
401
422
# the basis tree *may* be a ghost or a low level error may have
402
# occured. If the revision is present, its a problem, if its not
423
# occurred. If the revision is present, its a problem, if its not
404
425
if self.branch.repository.has_revision(revision_id):
406
427
# the basis tree is a ghost so return an empty tree.
407
return self.branch.repository.revision_tree(None)
428
return self.branch.repository.revision_tree(
429
_mod_revision.NULL_REVISION)
409
431
def _cleanup(self):
410
432
self._flush_ignore_list_cache()
412
434
def relpath(self, path):
413
435
"""Return the local path portion from a given path.
415
The path may be absolute or relative. If its a relative path it is
437
The path may be absolute or relative. If its a relative path it is
416
438
interpreted relative to the python current working directory.
418
440
return osutils.relpath(self.basedir, path)
420
442
def has_filename(self, filename):
421
443
return osutils.lexists(self.abspath(filename))
423
def get_file(self, file_id, path=None):
445
def get_file(self, file_id, path=None, filtered=True):
446
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
448
def get_file_with_stat(self, file_id, path=None, filtered=True,
450
"""See Tree.get_file_with_stat."""
425
452
path = self.id2path(file_id)
426
return self.get_file_byname(path)
428
def get_file_text(self, file_id):
429
return self.get_file(file_id).read()
431
def get_file_byname(self, filename):
432
return file(self.abspath(filename), 'rb')
453
file_obj = self.get_file_byname(path, filtered=False)
454
stat_value = _fstat(file_obj.fileno())
455
if filtered and self.supports_content_filtering():
456
filters = self._content_filter_stack(path)
457
file_obj = filtered_input_file(file_obj, filters)
458
return (file_obj, stat_value)
460
def get_file_text(self, file_id, path=None, filtered=True):
461
return self.get_file(file_id, path=path, filtered=filtered).read()
463
def get_file_byname(self, filename, filtered=True):
464
path = self.abspath(filename)
466
if filtered and self.supports_content_filtering():
467
filters = self._content_filter_stack(filename)
468
return filtered_input_file(f, filters)
472
def get_file_lines(self, file_id, path=None, filtered=True):
473
"""See Tree.get_file_lines()"""
474
file = self.get_file(file_id, path, filtered=filtered)
476
return file.readlines()
435
481
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
442
488
incorrectly attributed to CURRENT_REVISION (but after committing, the
443
489
attribution will be correct).
445
basis = self.basis_tree()
448
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
449
require_versioned=True).next()
450
changed_content, kind = changes[2], changes[6]
451
if not changed_content:
452
return basis.annotate_iter(file_id)
456
if kind[0] != 'file':
459
old_lines = list(basis.annotate_iter(file_id))
461
for tree in self.branch.repository.revision_trees(
462
self.get_parent_ids()[1:]):
463
if file_id not in tree:
465
old.append(list(tree.annotate_iter(file_id)))
466
return annotate.reannotate(old, self.get_file(file_id).readlines(),
491
maybe_file_parent_keys = []
492
for parent_id in self.get_parent_ids():
494
parent_tree = self.revision_tree(parent_id)
495
except errors.NoSuchRevisionInTree:
496
parent_tree = self.branch.repository.revision_tree(parent_id)
497
parent_tree.lock_read()
499
if file_id not in parent_tree:
501
ie = parent_tree.inventory[file_id]
502
if ie.kind != 'file':
503
# Note: this is slightly unnecessary, because symlinks and
504
# directories have a "text" which is the empty text, and we
505
# know that won't mess up annotations. But it seems cleaner
507
parent_text_key = (file_id, ie.revision)
508
if parent_text_key not in maybe_file_parent_keys:
509
maybe_file_parent_keys.append(parent_text_key)
512
graph = _mod_graph.Graph(self.branch.repository.texts)
513
heads = graph.heads(maybe_file_parent_keys)
514
file_parent_keys = []
515
for key in maybe_file_parent_keys:
517
file_parent_keys.append(key)
519
# Now we have the parents of this content
520
annotator = self.branch.repository.texts.get_annotator()
521
text = self.get_file(file_id).read()
522
this_key =(file_id, default_revision)
523
annotator.add_special_text(this_key, file_parent_keys, text)
524
annotations = [(key[-1], line)
525
for key, line in annotator.annotate_flat(this_key)]
471
528
def _get_ancestors(self, default_revision):
472
529
ancestors = set([default_revision])
509
566
def clone(self, to_bzrdir, revision_id=None):
510
567
"""Duplicate this working tree into to_bzr, including all state.
512
569
Specifically modified files are kept as modified, but
513
570
ignored and unknown files are discarded.
515
572
If you want to make a new line of development, see bzrdir.sprout()
518
If not None, the cloned tree will have its last revision set to
519
revision, and and difference between the source trees last revision
575
If not None, the cloned tree will have its last revision set to
576
revision, and difference between the source trees last revision
520
577
and this one merged in.
522
579
# assumes the target bzr dir format is compatible.
523
result = self._format.initialize(to_bzrdir)
580
result = to_bzrdir.create_workingtree()
524
581
self.copy_content_into(result, revision_id)
604
663
"""See MutableTree._add."""
605
664
# TODO: Re-adding a file that is removed in the working copy
606
665
# should probably put it back with the previous ID.
607
# the read and write working inventory should not occur in this
666
# the read and write working inventory should not occur in this
608
667
# function - they should be part of lock_write and unlock.
609
668
inv = self.inventory
610
669
for f, file_id, kind in zip(files, ids, kinds):
693
752
kind = _mapper(stat_result.st_mode)
694
753
if kind == 'file':
695
size = stat_result.st_size
696
# try for a stat cache lookup
697
executable = self._is_executable_from_path_and_stat(path, stat_result)
698
return (kind, size, executable, self._sha_from_stat(
754
return self._file_content_summary(path, stat_result)
700
755
elif kind == 'directory':
701
756
# perhaps it looks like a plain directory, but it's really a
704
759
kind = 'tree-reference'
705
760
return kind, None, None, None
706
761
elif kind == 'symlink':
707
return ('symlink', None, None, os.readlink(abspath))
762
target = osutils.readlink(abspath)
763
return ('symlink', None, None, target)
709
765
return (kind, None, None, None)
767
def _file_content_summary(self, path, stat_result):
768
size = stat_result.st_size
769
executable = self._is_executable_from_path_and_stat(path, stat_result)
770
# try for a stat cache lookup
771
return ('file', size, executable, self._sha_from_stat(
711
774
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
712
775
"""Common ghost checking functionality from set_parent_*.
723
786
def _set_merges_from_parent_ids(self, parent_ids):
724
787
merges = parent_ids[1:]
725
788
self._transport.put_bytes('pending-merges', '\n'.join(merges),
726
mode=self._control_files._file_mode)
789
mode=self.bzrdir._get_file_mode())
728
791
def _filter_parent_ids_by_ancestry(self, revision_ids):
729
792
"""Check that all merged revisions are proper 'heads'.
731
794
This will always return the first revision_id, and any merged revisions
734
797
if len(revision_ids) == 0:
735
798
return revision_ids
747
810
@needs_tree_write_lock
748
811
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
749
812
"""Set the parent ids to revision_ids.
751
814
See also set_parent_trees. This api will try to retrieve the tree data
752
815
for each element of revision_ids from the trees repository. If you have
753
816
tree data already available, it is more efficient to use
829
892
self._must_be_locked()
830
893
my_file = rio_file(stanzas, header)
831
894
self._transport.put_file(filename, my_file,
832
mode=self._control_files._file_mode)
895
mode=self.bzrdir._get_file_mode())
834
897
@needs_write_lock # because merge pulls data into the branch.
835
898
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
843
906
branch.last_revision().
845
908
from bzrlib.merge import Merger, Merge3Merger
846
pb = bzrlib.ui.ui_factory.nested_progress_bar()
909
pb = ui.ui_factory.nested_progress_bar()
848
911
merger = Merger(self.branch, this_tree=self, pb=pb)
849
912
merger.pp = ProgressPhase("Merge phase", 5, pb)
886
949
def merge_modified(self):
887
950
"""Return a dictionary of files modified by a merge.
889
The list is initialized by WorkingTree.set_merge_modified, which is
952
The list is initialized by WorkingTree.set_merge_modified, which is
890
953
typically called after we make some automatic updates to the tree
891
954
because of a merge.
897
960
hashfile = self._transport.get('merge-hashes')
898
961
except errors.NoSuchFile:
902
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
966
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
967
raise errors.MergeModifiedFormatError()
968
except StopIteration:
903
969
raise errors.MergeModifiedFormatError()
904
except StopIteration:
905
raise errors.MergeModifiedFormatError()
906
for s in RioReader(hashfile):
907
# RioReader reads in Unicode, so convert file_ids back to utf8
908
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
909
if file_id not in self.inventory:
911
text_hash = s.get("hash")
912
if text_hash == self.get_file_sha1(file_id):
913
merge_hashes[file_id] = text_hash
970
for s in RioReader(hashfile):
971
# RioReader reads in Unicode, so convert file_ids back to utf8
972
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
973
if file_id not in self.inventory:
975
text_hash = s.get("hash")
976
if text_hash == self.get_file_sha1(file_id):
977
merge_hashes[file_id] = text_hash
916
982
@needs_write_lock
917
983
def mkdir(self, path, file_id=None):
981
1049
def _directory_may_be_tree_reference(self, relpath):
982
# as a special case, if a directory contains control files then
1050
# as a special case, if a directory contains control files then
983
1051
# it's a tree reference, except that the root of the tree is not
984
1052
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
985
1053
# TODO: We could ask all the control formats whether they
1030
1098
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1032
1100
tree_bzrdir = branch_bzrdir
1033
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1101
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1034
1102
wt.set_parent_ids(self.get_parent_ids())
1035
1103
my_inv = self.inventory
1036
child_inv = Inventory(root_id=None)
1104
child_inv = inventory.Inventory(root_id=None)
1037
1105
new_root = my_inv[file_id]
1038
1106
my_inv.remove_recursive_id(file_id)
1039
1107
new_root.parent_id = None
1058
1126
self._serialize(self._inventory, sio)
1060
1128
self._transport.put_file('inventory', sio,
1061
mode=self._control_files._file_mode)
1129
mode=self.bzrdir._get_file_mode())
1062
1130
self._inventory_is_modified = False
1064
1132
def _kind(self, relpath):
1065
1133
return osutils.file_kind(self.abspath(relpath))
1067
def list_files(self, include_root=False):
1068
"""Recursively list all files as (path, class, kind, id, entry).
1135
def list_files(self, include_root=False, from_dir=None, recursive=True):
1136
"""List all files as (path, class, kind, id, entry).
1070
1138
Lists, but does not descend into unversioned directories.
1072
1139
This does not include files that have been deleted in this
1140
tree. Skips the control directory.
1075
Skips the control directory.
1142
:param include_root: if True, do not return an entry for the root
1143
:param from_dir: start from this directory or None for the root
1144
:param recursive: whether to recurse into subdirectories or not
1077
1146
# list_files is an iterator, so @needs_read_lock doesn't work properly
1078
1147
# with it. So callers should be careful to always read_lock the tree.
1080
1149
raise errors.ObjectNotLocked(self)
1082
1151
inv = self.inventory
1083
if include_root is True:
1152
if from_dir is None and include_root is True:
1084
1153
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1085
1154
# Convert these into local objects to save lookup times
1086
1155
pathjoin = osutils.pathjoin
1093
1162
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1095
1164
# directory file_id, relative path, absolute path, reverse sorted children
1096
children = os.listdir(self.basedir)
1165
if from_dir is not None:
1166
from_dir_id = inv.path2id(from_dir)
1167
if from_dir_id is None:
1168
# Directory not versioned
1170
from_dir_abspath = pathjoin(self.basedir, from_dir)
1172
from_dir_id = inv.root.file_id
1173
from_dir_abspath = self.basedir
1174
children = os.listdir(from_dir_abspath)
1097
1175
children.sort()
1098
# jam 20060527 The kernel sized tree seems equivalent whether we
1176
# jam 20060527 The kernel sized tree seems equivalent whether we
1099
1177
# use a deque and popleft to keep them sorted, or if we use a plain
1100
1178
# list and just reverse() them.
1101
1179
children = collections.deque(children)
1102
stack = [(inv.root.file_id, u'', self.basedir, children)]
1180
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1104
1182
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1159
1237
except KeyError:
1160
1238
yield fp[1:], c, fk, None, TreeEntry()
1163
1241
if fk != 'directory':
1166
# But do this child first
1167
new_children = os.listdir(fap)
1169
new_children = collections.deque(new_children)
1170
stack.append((f_ie.file_id, fp, fap, new_children))
1171
# Break out of inner loop,
1172
# so that we start outer loop with child
1244
# But do this child first if recursing down
1246
new_children = os.listdir(fap)
1248
new_children = collections.deque(new_children)
1249
stack.append((f_ie.file_id, fp, fap, new_children))
1250
# Break out of inner loop,
1251
# so that we start outer loop with child
1175
1254
# if we finished all children, pop it off the stack
1182
1261
to_dir must exist in the inventory.
1184
1263
If to_dir exists and is a directory, the files are moved into
1185
it, keeping their old names.
1264
it, keeping their old names.
1187
1266
Note that to_dir is only the last component of the new name;
1188
1267
this doesn't change the directory.
1316
1395
only_change_inv = True
1317
1396
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1318
1397
only_change_inv = False
1319
elif (sys.platform == 'win32'
1320
and from_rel.lower() == to_rel.lower()
1321
and self.has_filename(from_rel)):
1398
elif (not self.case_sensitive
1399
and from_rel.lower() == to_rel.lower()
1400
and self.has_filename(from_rel)):
1322
1401
only_change_inv = False
1324
1403
# something is wrong, so lets determine what exactly
1354
1433
inv = self.inventory
1355
1434
for entry in moved:
1357
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1436
self._move_entry(WorkingTree._RenameEntry(
1437
entry.to_rel, entry.from_id,
1358
1438
entry.to_tail, entry.to_parent_id, entry.from_rel,
1359
1439
entry.from_tail, entry.from_parent_id,
1360
1440
entry.only_change_inv))
1411
1491
from_tail = splitpath(from_rel)[-1]
1412
1492
from_id = inv.path2id(from_rel)
1413
1493
if from_id is None:
1414
raise errors.BzrRenameFailedError(from_rel,to_rel,
1415
errors.NotVersionedError(path=str(from_rel)))
1416
from_entry = inv[from_id]
1494
# if file is missing in the inventory maybe it's in the basis_tree
1495
basis_tree = self.branch.basis_tree()
1496
from_id = basis_tree.path2id(from_rel)
1498
raise errors.BzrRenameFailedError(from_rel,to_rel,
1499
errors.NotVersionedError(path=str(from_rel)))
1500
# put entry back in the inventory so we can rename it
1501
from_entry = basis_tree.inventory[from_id].copy()
1504
from_entry = inv[from_id]
1417
1505
from_parent_id = from_entry.parent_id
1418
1506
to_dir, to_tail = os.path.split(to_rel)
1419
1507
to_dir_id = inv.path2id(to_dir)
1465
1553
These are files in the working directory that are not versioned or
1466
1554
control files or ignored.
1468
# force the extras method to be fully executed before returning, to
1556
# force the extras method to be fully executed before returning, to
1469
1557
# prevent race conditions with the lock
1471
1559
[subp for subp in self.extras() if not self.is_ignored(subp)])
1481
1569
:raises: NoSuchId if any fileid is not currently versioned.
1483
1571
for file_id in file_ids:
1572
if file_id not in self._inventory:
1573
raise errors.NoSuchId(self, file_id)
1574
for file_id in file_ids:
1484
1575
if self._inventory.has_id(file_id):
1485
1576
self._inventory.remove_recursive_id(file_id)
1487
raise errors.NoSuchId(self, file_id)
1488
1577
if len(file_ids):
1489
# in the future this should just set a dirty bit to wait for the
1578
# in the future this should just set a dirty bit to wait for the
1490
1579
# final unlock. However, until all methods of workingtree start
1491
# with the current in -memory inventory rather than triggering
1580
# with the current in -memory inventory rather than triggering
1492
1581
# a read, it is more complex - we need to teach read_inventory
1493
1582
# to know when to read, and when to not read first... and possibly
1494
1583
# to save first when the in memory one may be corrupted.
1495
1584
# so for now, we just only write it if it is indeed dirty.
1496
1585
# - RBC 20060907
1497
1586
self._write_inventory(self._inventory)
1499
1588
def _iter_conflicts(self):
1500
1589
conflicted = set()
1501
1590
for info in self.list_files():
1510
1599
@needs_write_lock
1511
1600
def pull(self, source, overwrite=False, stop_revision=None,
1512
change_reporter=None, possible_transports=None):
1513
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1601
change_reporter=None, possible_transports=None, local=False):
1602
top_pb = ui.ui_factory.nested_progress_bar()
1514
1603
source.lock_read()
1516
1605
pp = ProgressPhase("Pull phase", 2, top_pb)
1518
1607
old_revision_info = self.branch.last_revision_info()
1519
1608
basis_tree = self.basis_tree()
1520
1609
count = self.branch.pull(source, overwrite, stop_revision,
1521
possible_transports=possible_transports)
1610
possible_transports=possible_transports,
1522
1612
new_revision_info = self.branch.last_revision_info()
1523
1613
if new_revision_info != old_revision_info:
1524
1614
pp.next_phase()
1525
1615
repository = self.branch.repository
1526
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1616
pb = ui.ui_factory.nested_progress_bar()
1527
1617
basis_tree.lock_read()
1529
1619
new_basis_tree = self.branch.basis_tree()
1534
1624
this_tree=self,
1536
1626
change_reporter=change_reporter)
1537
if (basis_tree.inventory.root is None and
1538
new_basis_tree.inventory.root is not None):
1539
self.set_root_id(new_basis_tree.get_root_id())
1627
basis_root_id = basis_tree.get_root_id()
1628
new_root_id = new_basis_tree.get_root_id()
1629
if basis_root_id != new_root_id:
1630
self.set_root_id(new_root_id)
1542
1633
basis_tree.unlock()
1544
1635
# reuse the revisiontree we merged against to set the new
1546
1637
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1547
# we have to pull the merge trees out again, because
1548
# merge_inner has set the ids. - this corner is not yet
1638
# we have to pull the merge trees out again, because
1639
# merge_inner has set the ids. - this corner is not yet
1549
1640
# layered well enough to prevent double handling.
1550
1641
# XXX TODO: Fix the double handling: telling the tree about
1551
1642
# the already known parent data is wasteful.
1781
1872
path = self._basis_inventory_name()
1782
1873
sio = StringIO(xml)
1783
1874
self._transport.put_file(path, sio,
1784
mode=self._control_files._file_mode)
1875
mode=self.bzrdir._get_file_mode())
1786
1877
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1787
1878
"""Create the text that will be saved in basis-inventory"""
1794
1885
# as commit already has that ready-to-use [while the format is the
1795
1886
# same, that is].
1797
# this double handles the inventory - unpack and repack -
1888
# this double handles the inventory - unpack and repack -
1798
1889
# but is easier to understand. We can/should put a conditional
1799
1890
# in here based on whether the inventory is in the latest format
1800
1891
# - perhaps we should repack all inventories on a repository
1802
1893
# the fast path is to copy the raw xml from the repository. If the
1803
# xml contains 'revision_id="', then we assume the right
1894
# xml contains 'revision_id="', then we assume the right
1804
1895
# revision_id is set. We must check for this full string, because a
1805
1896
# root node id can legitimately look like 'revision_id' but cannot
1806
1897
# contain a '"'.
1807
1898
xml = self.branch.repository.get_inventory_xml(new_revision)
1808
1899
firstline = xml.split('\n', 1)[0]
1809
if (not 'revision_id="' in firstline or
1900
if (not 'revision_id="' in firstline or
1810
1901
'format="7"' not in firstline):
1811
inv = self.branch.repository.deserialise_inventory(
1902
inv = self.branch.repository._serializer.read_inventory_from_string(
1813
1904
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1814
1905
self._write_basis_inventory(xml)
1815
1906
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1819
1910
"""Read the cached basis inventory."""
1820
1911
path = self._basis_inventory_name()
1821
1912
return self._transport.get_bytes(path)
1823
1914
@needs_read_lock
1824
1915
def read_working_inventory(self):
1825
1916
"""Read the working inventory.
1827
1918
:raises errors.InventoryModified: read_working_inventory will fail
1828
1919
when the current in memory inventory has been modified.
1830
# conceptually this should be an implementation detail of the tree.
1921
# conceptually this should be an implementation detail of the tree.
1831
1922
# XXX: Deprecate this.
1832
1923
# ElementTree does its own conversion from UTF-8, so open in
1859
1950
# Recurse directory and add all files
1860
1951
# so we can check if they have changed.
1861
1952
for parent_info, file_infos in\
1862
osutils.walkdirs(self.abspath(directory),
1864
for relpath, basename, kind, lstat, abspath in file_infos:
1953
self.walkdirs(directory):
1954
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1865
1955
# Is it versioned or ignored?
1866
1956
if self.path2id(relpath) or self.is_ignored(relpath):
1867
1957
# Add nested content for deletion.
1917
2006
tree_delta.unversioned.extend((unknown_file,))
1918
2007
raise errors.BzrRemoveChangedFilesError(tree_delta)
1920
# Build inv_delta and delete files where applicaple,
2009
# Build inv_delta and delete files where applicable,
1921
2010
# do this before any modifications to inventory.
1922
2011
for f in files:
1923
2012
fid = self.path2id(f)
2032
2120
name = os.path.basename(path)
2035
# fixme, there should be a factory function inv,add_??
2123
# fixme, there should be a factory function inv,add_??
2036
2124
if kind == 'directory':
2037
2125
inv.add(InventoryDirectory(file_id, name, parent))
2038
2126
elif kind == 'file':
2056
2144
def _set_root_id(self, file_id):
2057
2145
"""Set the root id for this tree, in a format specific manner.
2059
:param file_id: The file id to assign to the root. It must not be
2147
:param file_id: The file id to assign to the root. It must not be
2060
2148
present in the current inventory or an error will occur. It must
2061
2149
not be None, but rather a valid file id.
2082
2170
def unlock(self):
2083
2171
"""See Branch.unlock.
2085
2173
WorkingTree locking just uses the Branch locking facilities.
2086
2174
This is current because all working trees have an embedded branch
2087
2175
within them. IF in the future, we were to make branch data shareable
2088
between multiple working trees, i.e. via shared storage, then we
2176
between multiple working trees, i.e. via shared storage, then we
2089
2177
would probably want to lock both the local tree, and the branch.
2091
2179
raise NotImplementedError(self.unlock)
2143
2231
# cant set that until we update the working trees last revision to be
2144
2232
# one from the new branch, because it will just get absorbed by the
2145
2233
# parent de-duplication logic.
2147
2235
# We MUST save it even if an error occurs, because otherwise the users
2148
2236
# local work is unreferenced and will appear to have been lost.
2152
2240
last_rev = self.get_parent_ids()[0]
2158
2246
basis.lock_read()
2160
2248
to_tree = self.branch.basis_tree()
2161
if basis.inventory.root is None:
2162
self.set_root_id(to_tree.get_root_id())
2249
to_root_id = to_tree.get_root_id()
2250
if (basis.inventory.root is None
2251
or basis.inventory.root.file_id != to_root_id):
2252
self.set_root_id(to_root_id)
2164
2254
result += merge.merge_inner(
2174
2264
parent_trees = [(self.branch.last_revision(), to_tree)]
2175
2265
merges = self.get_parent_ids()[1:]
2176
2266
# Ideally we ask the tree for the trees here, that way the working
2177
# tree can decide whether to give us teh entire tree or give us a
2267
# tree can decide whether to give us the entire tree or give us a
2178
2268
# lazy initialised tree. dirstate for instance will have the trees
2179
2269
# in ram already, whereas a last-revision + basis-inventory tree
2180
2270
# will not, but also does not need them when setting parents.
2323
2413
bzrdir_loc = bisect_left(cur_disk_dir_content,
2324
2414
('.bzr', '.bzr'))
2325
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2415
if (bzrdir_loc < len(cur_disk_dir_content)
2416
and self.bzrdir.is_control_filename(
2417
cur_disk_dir_content[bzrdir_loc][0])):
2326
2418
# we dont yield the contents of, or, .bzr itself.
2327
2419
del cur_disk_dir_content[bzrdir_loc]
2328
2420
if inv_finished:
2419
2511
# FIXME: stash the node in pending
2420
2512
entry = inv[top_id]
2421
for name, child in entry.sorted_children():
2422
dirblock.append((relroot + name, name, child.kind, None,
2423
child.file_id, child.kind
2513
if entry.kind == 'directory':
2514
for name, child in entry.sorted_children():
2515
dirblock.append((relroot + name, name, child.kind, None,
2516
child.file_id, child.kind
2425
2518
yield (currentdir[0], entry.file_id), dirblock
2426
2519
# push the user specified dirs from dirblock
2427
2520
for dir in reversed(dirblock):
2461
2554
return un_resolved, resolved
2463
2556
@needs_read_lock
2557
def _check(self, references):
2558
"""Check the tree for consistency.
2560
:param references: A dict with keys matching the items returned by
2561
self._get_check_refs(), and values from looking those keys up in
2465
2564
tree_basis = self.basis_tree()
2466
2565
tree_basis.lock_read()
2468
repo_basis = self.branch.repository.revision_tree(
2469
self.last_revision())
2567
repo_basis = references[('trees', self.last_revision())]
2470
2568
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2471
2569
raise errors.BzrCheckError(
2472
2570
"Mismatched basis inventory content.")
2493
2591
self)._get_rules_searcher(default_searcher)
2494
2592
return self._rules_searcher
2594
def get_shelf_manager(self):
2595
"""Return the ShelfManager for this WorkingTree."""
2596
from bzrlib.shelf import ShelfManager
2597
return ShelfManager(self, self._transport)
2497
2600
class WorkingTree2(WorkingTree):
2498
2601
"""This is the Format 2 working tree.
2500
This was the first weave based working tree.
2603
This was the first weave based working tree.
2501
2604
- uses os locks for locking.
2502
2605
- uses the branch last-revision.
2513
2616
if self._inventory is None:
2514
2617
self.read_working_inventory()
2619
def _get_check_refs(self):
2620
"""Return the references needed to perform a check of this tree."""
2621
return [('trees', self.last_revision())]
2516
2623
def lock_tree_write(self):
2517
2624
"""See WorkingTree.lock_tree_write().
2565
2672
def _change_last_revision(self, revision_id):
2566
2673
"""See WorkingTree._change_last_revision."""
2567
if revision_id is None or revision_id == NULL_REVISION:
2674
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2569
2676
self._transport.delete('last-revision')
2570
2677
except errors.NoSuchFile:
2574
2681
self._transport.put_bytes('last-revision', revision_id,
2575
mode=self._control_files._file_mode)
2682
mode=self.bzrdir._get_file_mode())
2685
def _get_check_refs(self):
2686
"""Return the references needed to perform a check of this tree."""
2687
return [('trees', self.last_revision())]
2578
2689
@needs_tree_write_lock
2579
2690
def set_conflicts(self, conflicts):
2580
self._put_rio('conflicts', conflicts.to_stanzas(),
2691
self._put_rio('conflicts', conflicts.to_stanzas(),
2581
2692
CONFLICT_HEADER_1)
2583
2694
@needs_tree_write_lock
2594
2705
except errors.NoSuchFile:
2595
2706
return _mod_conflicts.ConflictList()
2597
if confile.next() != CONFLICT_HEADER_1 + '\n':
2709
if confile.next() != CONFLICT_HEADER_1 + '\n':
2710
raise errors.ConflictFormatError()
2711
except StopIteration:
2598
2712
raise errors.ConflictFormatError()
2599
except StopIteration:
2600
raise errors.ConflictFormatError()
2601
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2713
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2603
2717
def unlock(self):
2604
2718
# do non-implementation specific cleanup
2629
2743
* a format string,
2630
2744
* an open routine.
2632
Formats are placed in an dict by their format string for reference
2746
Formats are placed in an dict by their format string for reference
2633
2747
during workingtree opening. Its not required that these be instances, they
2634
can be classes themselves with class methods - it simply depends on
2748
can be classes themselves with class methods - it simply depends on
2635
2749
whether state is needed for a given format or not.
2637
2751
Once a format is deprecated, just deprecate the initialize and open
2638
methods on the format class. Do not deprecate the object, as the
2752
methods on the format class. Do not deprecate the object, as the
2639
2753
object will be created every time regardless.
2685
2799
"""Is this format supported?
2687
2801
Supported formats can be initialized and opened.
2688
Unsupported formats may not support initialization or committing or
2802
Unsupported formats may not support initialization or committing or
2689
2803
some other features depending on the reason for not being supported.
2807
def supports_content_filtering(self):
2808
"""True if this format supports content filtering."""
2811
def supports_views(self):
2812
"""True if this format supports stored views."""
2694
2816
def register_format(klass, format):
2695
2817
klass._formats[format.get_format_string()] = format
2715
2837
"""See WorkingTreeFormat.get_format_description()."""
2716
2838
return "Working tree format 2"
2718
def _stub_initialize_remote(self, branch):
2719
"""As a special workaround create critical control files for a remote working tree.
2840
def _stub_initialize_on_transport(self, transport, file_mode):
2841
"""Workaround: create control files for a remote working tree.
2721
2843
This ensures that it can later be updated and dealt with locally,
2722
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2844
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2723
2845
no working tree. (See bug #43064).
2725
2847
sio = StringIO()
2848
inv = inventory.Inventory()
2727
2849
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2729
branch._transport.put_file('inventory', sio,
2730
mode=branch.control_files._file_mode)
2731
branch._transport.put_bytes('pending-merges', '',
2732
mode=branch.control_files._file_mode)
2851
transport.put_file('inventory', sio, file_mode)
2852
transport.put_bytes('pending-merges', '', file_mode)
2735
2854
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2736
2855
accelerator_tree=None, hardlink=False):
2823
2942
def _open_control_files(self, a_bzrdir):
2824
2943
transport = a_bzrdir.get_workingtree_transport(None)
2825
return LockableFiles(transport, self._lock_file_name,
2944
return LockableFiles(transport, self._lock_file_name,
2826
2945
self._lock_class)
2828
2947
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2829
2948
accelerator_tree=None, hardlink=False):
2830
2949
"""See WorkingTreeFormat.initialize().
2832
2951
:param revision_id: if supplied, create a working tree at a different
2833
2952
revision than the branch is at.
2834
2953
:param accelerator_tree: A tree which can be used for retrieving file
2845
2964
control_files.create_lock()
2846
2965
control_files.lock_write()
2847
2966
transport.put_bytes('format', self.get_format_string(),
2848
mode=control_files._file_mode)
2967
mode=a_bzrdir._get_file_mode())
2849
2968
if from_branch is not None:
2850
2969
branch = from_branch
2871
2990
# only set an explicit root id if there is one to set.
2872
2991
if basis_tree.inventory.root is not None:
2873
2992
wt.set_root_id(basis_tree.get_root_id())
2874
if revision_id == NULL_REVISION:
2993
if revision_id == _mod_revision.NULL_REVISION:
2875
2994
wt.set_parent_trees([])
2877
2996
wt.set_parent_trees([(revision_id, basis_tree)])
2919
3038
return self.get_format_string()
2922
__default_format = WorkingTreeFormat4()
3041
__default_format = WorkingTreeFormat6()
2923
3042
WorkingTreeFormat.register_format(__default_format)
3043
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3044
WorkingTreeFormat.register_format(WorkingTreeFormat4())
2924
3045
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2925
3046
WorkingTreeFormat.set_default_format(__default_format)
2926
3047
# formats which have no format string are not discoverable