1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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,
76
79
import bzrlib.branch
77
80
from bzrlib.transport import get_transport
78
from bzrlib.workingtree_4 import (
82
from bzrlib.workingtree_4 import WorkingTreeFormat4
85
85
from bzrlib import symbol_versioning
86
86
from bzrlib.decorators import needs_read_lock, needs_write_lock
87
from bzrlib.lockable_files import LockableFiles
87
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
88
from bzrlib.lockable_files import LockableFiles, TransportLock
88
89
from bzrlib.lockdir import LockDir
89
90
import bzrlib.mutabletree
90
91
from bzrlib.mutabletree import needs_tree_write_lock
91
92
from bzrlib import osutils
92
93
from bzrlib.osutils import (
100
103
supports_executable,
102
from bzrlib.filters import filtered_input_file
103
105
from bzrlib.trace import mutter, note
104
106
from bzrlib.transport.local import LocalTransport
105
107
from bzrlib.progress import DummyProgress, ProgressPhase
106
from bzrlib.revision import CURRENT_REVISION
108
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
107
109
from bzrlib.rio import RioReader, rio_file, Stanza
108
from bzrlib.symbol_versioning import (
110
DEPRECATED_PARAMETER,
110
from bzrlib.symbol_versioning import (deprecated_passed,
113
DEPRECATED_PARAMETER,
114
117
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
120
123
class TreeEntry(object):
121
124
"""An entry that implements the minimum interface used by commands.
123
This needs further inspection, it may be better to have
126
This needs further inspection, it may be better to have
124
127
InventoryEntries without ids - though that seems wrong. For now,
125
128
this is a parallel hierarchy to InventoryEntry, and needs to become
126
129
one of several things: decorates to that hierarchy, children of, or
129
132
no InventoryEntry available - i.e. for unversioned objects.
130
133
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
133
136
def __eq__(self, other):
134
137
# yes, this us ugly, TODO: best practice __eq__ style.
135
138
return (isinstance(other, TreeEntry)
136
139
and other.__class__ == self.__class__)
138
141
def kind_character(self):
182
185
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)
189
188
def __init__(self, basedir='.',
190
189
branch=DEPRECATED_PARAMETER,
226
225
wt_trans = self.bzrdir.get_workingtree_transport(None)
227
226
cache_filename = wt_trans.local_abspath('stat-cache')
228
227
self._hashcache = hashcache.HashCache(basedir, cache_filename,
229
self.bzrdir._get_file_mode(),
230
self._content_filter_stack_provider())
228
self.bzrdir._get_file_mode())
231
229
hc = self._hashcache
233
231
# is this scan needed ? it makes things kinda slow.
249
247
self._set_inventory(_inventory, dirty=False)
250
248
self._detect_case_handling()
251
249
self._rules_searcher = None
252
self.views = self._make_views()
254
251
def _detect_case_handling(self):
255
252
wt_trans = self.bzrdir.get_workingtree_transport(None)
281
278
self._control_files.break_lock()
282
279
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.
294
281
def requires_rich_root(self):
295
282
return self._format.requires_rich_root
297
284
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()
306
287
def _set_inventory(self, inv, dirty):
307
288
"""Set the internal cached inventory.
325
path = osutils.getcwd()
306
path = os.path.getcwdu()
326
307
control = bzrdir.BzrDir.open(path, _unsupported)
327
308
return control.open_workingtree(_unsupported)
330
311
def open_containing(path=None):
331
312
"""Open an existing working tree which has its root about path.
333
314
This probes for a working tree at path and searches upwards from there.
335
316
Basically we keep looking up until we find the control directory or
397
378
def basis_tree(self):
398
379
"""Return RevisionTree for the current last revision.
400
381
If the left most parent is a ghost then the returned tree will be an
401
empty tree - one obtained by calling
402
repository.revision_tree(NULL_REVISION).
382
empty tree - one obtained by calling repository.revision_tree(None).
405
385
revision_id = self.get_parent_ids()[0]
407
387
# no parents, return an empty revision tree.
408
388
# in the future this should return the tree for
409
389
# 'empty:' - the implicit root empty tree.
410
return self.branch.repository.revision_tree(
411
_mod_revision.NULL_REVISION)
390
return self.branch.repository.revision_tree(None)
413
392
return self.revision_tree(revision_id)
414
393
except errors.NoSuchRevision:
420
399
return self.branch.repository.revision_tree(revision_id)
421
400
except (errors.RevisionNotPresent, errors.NoSuchRevision):
422
401
# the basis tree *may* be a ghost or a low level error may have
423
# occurred. If the revision is present, its a problem, if its not
402
# occured. If the revision is present, its a problem, if its not
425
404
if self.branch.repository.has_revision(revision_id):
427
406
# the basis tree is a ghost so return an empty tree.
428
return self.branch.repository.revision_tree(
429
_mod_revision.NULL_REVISION)
407
return self.branch.repository.revision_tree(None)
431
409
def _cleanup(self):
432
410
self._flush_ignore_list_cache()
434
412
def relpath(self, path):
435
413
"""Return the local path portion from a given path.
437
The path may be absolute or relative. If its a relative path it is
415
The path may be absolute or relative. If its a relative path it is
438
416
interpreted relative to the python current working directory.
440
418
return osutils.relpath(self.basedir, path)
442
420
def has_filename(self, filename):
443
421
return osutils.lexists(self.abspath(filename))
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."""
423
def get_file(self, file_id, path=None):
452
425
path = self.id2path(file_id)
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()
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')
481
435
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
488
442
incorrectly attributed to CURRENT_REVISION (but after committing, the
489
443
attribution will be correct).
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)]
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(),
528
471
def _get_ancestors(self, default_revision):
529
472
ancestors = set([default_revision])
566
509
def clone(self, to_bzrdir, revision_id=None):
567
510
"""Duplicate this working tree into to_bzr, including all state.
569
512
Specifically modified files are kept as modified, but
570
513
ignored and unknown files are discarded.
572
515
If you want to make a new line of development, see bzrdir.sprout()
575
If not None, the cloned tree will have its last revision set to
576
revision, and difference between the source trees last revision
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
577
520
and this one merged in.
579
522
# assumes the target bzr dir format is compatible.
661
604
"""See MutableTree._add."""
662
605
# TODO: Re-adding a file that is removed in the working copy
663
606
# should probably put it back with the previous ID.
664
# the read and write working inventory should not occur in this
607
# the read and write working inventory should not occur in this
665
608
# function - they should be part of lock_write and unlock.
666
609
inv = self.inventory
667
610
for f, file_id, kind in zip(files, ids, kinds):
761
704
kind = 'tree-reference'
762
705
return kind, None, None, None
763
706
elif kind == 'symlink':
764
target = osutils.readlink(abspath)
765
return ('symlink', None, None, target)
707
return ('symlink', None, None, os.readlink(abspath))
767
709
return (kind, None, None, None)
781
723
def _set_merges_from_parent_ids(self, parent_ids):
782
724
merges = parent_ids[1:]
783
725
self._transport.put_bytes('pending-merges', '\n'.join(merges),
784
mode=self.bzrdir._get_file_mode())
726
mode=self._control_files._file_mode)
786
728
def _filter_parent_ids_by_ancestry(self, revision_ids):
787
729
"""Check that all merged revisions are proper 'heads'.
789
731
This will always return the first revision_id, and any merged revisions
792
734
if len(revision_ids) == 0:
793
735
return revision_ids
805
747
@needs_tree_write_lock
806
748
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
807
749
"""Set the parent ids to revision_ids.
809
751
See also set_parent_trees. This api will try to retrieve the tree data
810
752
for each element of revision_ids from the trees repository. If you have
811
753
tree data already available, it is more efficient to use
887
829
self._must_be_locked()
888
830
my_file = rio_file(stanzas, header)
889
831
self._transport.put_file(filename, my_file,
890
mode=self.bzrdir._get_file_mode())
832
mode=self._control_files._file_mode)
892
834
@needs_write_lock # because merge pulls data into the branch.
893
835
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
901
843
branch.last_revision().
903
845
from bzrlib.merge import Merger, Merge3Merger
904
pb = ui.ui_factory.nested_progress_bar()
846
pb = bzrlib.ui.ui_factory.nested_progress_bar()
906
848
merger = Merger(self.branch, this_tree=self, pb=pb)
907
849
merger.pp = ProgressPhase("Merge phase", 5, pb)
944
886
def merge_modified(self):
945
887
"""Return a dictionary of files modified by a merge.
947
The list is initialized by WorkingTree.set_merge_modified, which is
889
The list is initialized by WorkingTree.set_merge_modified, which is
948
890
typically called after we make some automatic updates to the tree
949
891
because of a merge.
955
897
hashfile = self._transport.get('merge-hashes')
956
898
except errors.NoSuchFile:
961
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
962
raise errors.MergeModifiedFormatError()
963
except StopIteration:
902
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
964
903
raise errors.MergeModifiedFormatError()
965
for s in RioReader(hashfile):
966
# RioReader reads in Unicode, so convert file_ids back to utf8
967
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
968
if file_id not in self.inventory:
970
text_hash = s.get("hash")
971
if text_hash == self.get_file_sha1(file_id):
972
merge_hashes[file_id] = text_hash
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
977
916
@needs_write_lock
978
917
def mkdir(self, path, file_id=None):
1044
981
def _directory_may_be_tree_reference(self, relpath):
1045
# as a special case, if a directory contains control files then
982
# as a special case, if a directory contains control files then
1046
983
# it's a tree reference, except that the root of the tree is not
1047
984
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1048
985
# TODO: We could ask all the control formats whether they
1093
1030
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1095
1032
tree_bzrdir = branch_bzrdir
1096
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1033
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1097
1034
wt.set_parent_ids(self.get_parent_ids())
1098
1035
my_inv = self.inventory
1099
child_inv = inventory.Inventory(root_id=None)
1036
child_inv = Inventory(root_id=None)
1100
1037
new_root = my_inv[file_id]
1101
1038
my_inv.remove_recursive_id(file_id)
1102
1039
new_root.parent_id = None
1121
1058
self._serialize(self._inventory, sio)
1123
1060
self._transport.put_file('inventory', sio,
1124
mode=self.bzrdir._get_file_mode())
1061
mode=self._control_files._file_mode)
1125
1062
self._inventory_is_modified = False
1127
1064
def _kind(self, relpath):
1128
1065
return osutils.file_kind(self.abspath(relpath))
1130
def list_files(self, include_root=False, from_dir=None, recursive=True):
1131
"""List all files as (path, class, kind, id, entry).
1067
def list_files(self, include_root=False):
1068
"""Recursively list all files as (path, class, kind, id, entry).
1133
1070
Lists, but does not descend into unversioned directories.
1134
1072
This does not include files that have been deleted in this
1135
tree. Skips the control directory.
1137
:param include_root: if True, do not return an entry for the root
1138
:param from_dir: start from this directory or None for the root
1139
:param recursive: whether to recurse into subdirectories or not
1075
Skips the control directory.
1141
1077
# list_files is an iterator, so @needs_read_lock doesn't work properly
1142
1078
# with it. So callers should be careful to always read_lock the tree.
1144
1080
raise errors.ObjectNotLocked(self)
1146
1082
inv = self.inventory
1147
if from_dir is None and include_root is True:
1083
if include_root is True:
1148
1084
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1149
1085
# Convert these into local objects to save lookup times
1150
1086
pathjoin = osutils.pathjoin
1157
1093
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1159
1095
# directory file_id, relative path, absolute path, reverse sorted children
1160
if from_dir is not None:
1161
from_dir_id = inv.path2id(from_dir)
1162
if from_dir_id is None:
1163
# Directory not versioned
1165
from_dir_abspath = pathjoin(self.basedir, from_dir)
1167
from_dir_id = inv.root.file_id
1168
from_dir_abspath = self.basedir
1169
children = os.listdir(from_dir_abspath)
1096
children = os.listdir(self.basedir)
1170
1097
children.sort()
1171
# jam 20060527 The kernel sized tree seems equivalent whether we
1098
# jam 20060527 The kernel sized tree seems equivalent whether we
1172
1099
# use a deque and popleft to keep them sorted, or if we use a plain
1173
1100
# list and just reverse() them.
1174
1101
children = collections.deque(children)
1175
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1102
stack = [(inv.root.file_id, u'', self.basedir, children)]
1177
1104
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1232
1159
except KeyError:
1233
1160
yield fp[1:], c, fk, None, TreeEntry()
1236
1163
if fk != 'directory':
1239
# But do this child first if recursing down
1241
new_children = os.listdir(fap)
1243
new_children = collections.deque(new_children)
1244
stack.append((f_ie.file_id, fp, fap, new_children))
1245
# Break out of inner loop,
1246
# so that we start outer loop with child
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
1249
1175
# if we finished all children, pop it off the stack
1256
1182
to_dir must exist in the inventory.
1258
1184
If to_dir exists and is a directory, the files are moved into
1259
it, keeping their old names.
1185
it, keeping their old names.
1261
1187
Note that to_dir is only the last component of the new name;
1262
1188
this doesn't change the directory.
1428
1354
inv = self.inventory
1429
1355
for entry in moved:
1431
self._move_entry(WorkingTree._RenameEntry(
1432
entry.to_rel, entry.from_id,
1357
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1433
1358
entry.to_tail, entry.to_parent_id, entry.from_rel,
1434
1359
entry.from_tail, entry.from_parent_id,
1435
1360
entry.only_change_inv))
1486
1411
from_tail = splitpath(from_rel)[-1]
1487
1412
from_id = inv.path2id(from_rel)
1488
1413
if from_id is None:
1489
# if file is missing in the inventory maybe it's in the basis_tree
1490
basis_tree = self.branch.basis_tree()
1491
from_id = basis_tree.path2id(from_rel)
1493
raise errors.BzrRenameFailedError(from_rel,to_rel,
1494
errors.NotVersionedError(path=str(from_rel)))
1495
# put entry back in the inventory so we can rename it
1496
from_entry = basis_tree.inventory[from_id].copy()
1499
from_entry = inv[from_id]
1414
raise errors.BzrRenameFailedError(from_rel,to_rel,
1415
errors.NotVersionedError(path=str(from_rel)))
1416
from_entry = inv[from_id]
1500
1417
from_parent_id = from_entry.parent_id
1501
1418
to_dir, to_tail = os.path.split(to_rel)
1502
1419
to_dir_id = inv.path2id(to_dir)
1548
1465
These are files in the working directory that are not versioned or
1549
1466
control files or ignored.
1551
# force the extras method to be fully executed before returning, to
1468
# force the extras method to be fully executed before returning, to
1552
1469
# prevent race conditions with the lock
1554
1471
[subp for subp in self.extras() if not self.is_ignored(subp)])
1564
1481
:raises: NoSuchId if any fileid is not currently versioned.
1566
1483
for file_id in file_ids:
1567
if file_id not in self._inventory:
1568
raise errors.NoSuchId(self, file_id)
1569
for file_id in file_ids:
1570
1484
if self._inventory.has_id(file_id):
1571
1485
self._inventory.remove_recursive_id(file_id)
1487
raise errors.NoSuchId(self, file_id)
1572
1488
if len(file_ids):
1573
# in the future this should just set a dirty bit to wait for the
1489
# in the future this should just set a dirty bit to wait for the
1574
1490
# final unlock. However, until all methods of workingtree start
1575
# with the current in -memory inventory rather than triggering
1491
# with the current in -memory inventory rather than triggering
1576
1492
# a read, it is more complex - we need to teach read_inventory
1577
1493
# to know when to read, and when to not read first... and possibly
1578
1494
# to save first when the in memory one may be corrupted.
1579
1495
# so for now, we just only write it if it is indeed dirty.
1580
1496
# - RBC 20060907
1581
1497
self._write_inventory(self._inventory)
1583
1499
def _iter_conflicts(self):
1584
1500
conflicted = set()
1585
1501
for info in self.list_files():
1594
1510
@needs_write_lock
1595
1511
def pull(self, source, overwrite=False, stop_revision=None,
1596
change_reporter=None, possible_transports=None, local=False):
1597
top_pb = ui.ui_factory.nested_progress_bar()
1512
change_reporter=None, possible_transports=None):
1513
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1598
1514
source.lock_read()
1600
1516
pp = ProgressPhase("Pull phase", 2, top_pb)
1602
1518
old_revision_info = self.branch.last_revision_info()
1603
1519
basis_tree = self.basis_tree()
1604
1520
count = self.branch.pull(source, overwrite, stop_revision,
1605
possible_transports=possible_transports,
1521
possible_transports=possible_transports)
1607
1522
new_revision_info = self.branch.last_revision_info()
1608
1523
if new_revision_info != old_revision_info:
1609
1524
pp.next_phase()
1610
1525
repository = self.branch.repository
1611
pb = ui.ui_factory.nested_progress_bar()
1526
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1612
1527
basis_tree.lock_read()
1614
1529
new_basis_tree = self.branch.basis_tree()
1629
1544
# reuse the revisiontree we merged against to set the new
1631
1546
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1632
# we have to pull the merge trees out again, because
1633
# merge_inner has set the ids. - this corner is not yet
1547
# we have to pull the merge trees out again, because
1548
# merge_inner has set the ids. - this corner is not yet
1634
1549
# layered well enough to prevent double handling.
1635
1550
# XXX TODO: Fix the double handling: telling the tree about
1636
1551
# the already known parent data is wasteful.
1866
1781
path = self._basis_inventory_name()
1867
1782
sio = StringIO(xml)
1868
1783
self._transport.put_file(path, sio,
1869
mode=self.bzrdir._get_file_mode())
1784
mode=self._control_files._file_mode)
1871
1786
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1872
1787
"""Create the text that will be saved in basis-inventory"""
1879
1794
# as commit already has that ready-to-use [while the format is the
1880
1795
# same, that is].
1882
# this double handles the inventory - unpack and repack -
1797
# this double handles the inventory - unpack and repack -
1883
1798
# but is easier to understand. We can/should put a conditional
1884
1799
# in here based on whether the inventory is in the latest format
1885
1800
# - perhaps we should repack all inventories on a repository
1887
1802
# the fast path is to copy the raw xml from the repository. If the
1888
# xml contains 'revision_id="', then we assume the right
1803
# xml contains 'revision_id="', then we assume the right
1889
1804
# revision_id is set. We must check for this full string, because a
1890
1805
# root node id can legitimately look like 'revision_id' but cannot
1891
1806
# contain a '"'.
1892
1807
xml = self.branch.repository.get_inventory_xml(new_revision)
1893
1808
firstline = xml.split('\n', 1)[0]
1894
if (not 'revision_id="' in firstline or
1809
if (not 'revision_id="' in firstline or
1895
1810
'format="7"' not in firstline):
1896
1811
inv = self.branch.repository.deserialise_inventory(
1897
1812
new_revision, xml)
1904
1819
"""Read the cached basis inventory."""
1905
1820
path = self._basis_inventory_name()
1906
1821
return self._transport.get_bytes(path)
1908
1823
@needs_read_lock
1909
1824
def read_working_inventory(self):
1910
1825
"""Read the working inventory.
1912
1827
:raises errors.InventoryModified: read_working_inventory will fail
1913
1828
when the current in memory inventory has been modified.
1915
# conceptually this should be an implementation detail of the tree.
1830
# conceptually this should be an implementation detail of the tree.
1916
1831
# XXX: Deprecate this.
1917
1832
# ElementTree does its own conversion from UTF-8, so open in
2000
1915
tree_delta.unversioned.extend((unknown_file,))
2001
1916
raise errors.BzrRemoveChangedFilesError(tree_delta)
2003
# Build inv_delta and delete files where applicable,
1918
# Build inv_delta and delete files where applicaple,
2004
1919
# do this before any modifications to inventory.
2005
1920
for f in files:
2006
1921
fid = self.path2id(f)
2114
2030
name = os.path.basename(path)
2117
# fixme, there should be a factory function inv,add_??
2033
# fixme, there should be a factory function inv,add_??
2118
2034
if kind == 'directory':
2119
2035
inv.add(InventoryDirectory(file_id, name, parent))
2120
2036
elif kind == 'file':
2138
2054
def _set_root_id(self, file_id):
2139
2055
"""Set the root id for this tree, in a format specific manner.
2141
:param file_id: The file id to assign to the root. It must not be
2057
:param file_id: The file id to assign to the root. It must not be
2142
2058
present in the current inventory or an error will occur. It must
2143
2059
not be None, but rather a valid file id.
2164
2080
def unlock(self):
2165
2081
"""See Branch.unlock.
2167
2083
WorkingTree locking just uses the Branch locking facilities.
2168
2084
This is current because all working trees have an embedded branch
2169
2085
within them. IF in the future, we were to make branch data shareable
2170
between multiple working trees, i.e. via shared storage, then we
2086
between multiple working trees, i.e. via shared storage, then we
2171
2087
would probably want to lock both the local tree, and the branch.
2173
2089
raise NotImplementedError(self.unlock)
2225
2141
# cant set that until we update the working trees last revision to be
2226
2142
# one from the new branch, because it will just get absorbed by the
2227
2143
# parent de-duplication logic.
2229
2145
# We MUST save it even if an error occurs, because otherwise the users
2230
2146
# local work is unreferenced and will appear to have been lost.
2234
2150
last_rev = self.get_parent_ids()[0]
2256
2172
parent_trees = [(self.branch.last_revision(), to_tree)]
2257
2173
merges = self.get_parent_ids()[1:]
2258
2174
# Ideally we ask the tree for the trees here, that way the working
2259
# tree can decide whether to give us the entire tree or give us a
2175
# tree can decide whether to give us teh entire tree or give us a
2260
2176
# lazy initialised tree. dirstate for instance will have the trees
2261
2177
# in ram already, whereas a last-revision + basis-inventory tree
2262
2178
# will not, but also does not need them when setting parents.
2405
2321
bzrdir_loc = bisect_left(cur_disk_dir_content,
2406
2322
('.bzr', '.bzr'))
2407
if (bzrdir_loc < len(cur_disk_dir_content)
2408
and self.bzrdir.is_control_filename(
2409
cur_disk_dir_content[bzrdir_loc][0])):
2323
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2410
2324
# we dont yield the contents of, or, .bzr itself.
2411
2325
del cur_disk_dir_content[bzrdir_loc]
2412
2326
if inv_finished:
2546
2460
return un_resolved, resolved
2548
2462
@needs_read_lock
2549
def _check(self, references):
2550
"""Check the tree for consistency.
2552
:param references: A dict with keys matching the items returned by
2553
self._get_check_refs(), and values from looking those keys up in
2556
2464
tree_basis = self.basis_tree()
2557
2465
tree_basis.lock_read()
2559
repo_basis = references[('trees', self.last_revision())]
2467
repo_basis = self.branch.repository.revision_tree(
2468
self.last_revision())
2560
2469
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2561
2470
raise errors.BzrCheckError(
2562
2471
"Mismatched basis inventory content.")
2583
2492
self)._get_rules_searcher(default_searcher)
2584
2493
return self._rules_searcher
2586
def get_shelf_manager(self):
2587
"""Return the ShelfManager for this WorkingTree."""
2588
from bzrlib.shelf import ShelfManager
2589
return ShelfManager(self, self._transport)
2592
2496
class WorkingTree2(WorkingTree):
2593
2497
"""This is the Format 2 working tree.
2595
This was the first weave based working tree.
2499
This was the first weave based working tree.
2596
2500
- uses os locks for locking.
2597
2501
- uses the branch last-revision.
2608
2512
if self._inventory is None:
2609
2513
self.read_working_inventory()
2611
def _get_check_refs(self):
2612
"""Return the references needed to perform a check of this tree."""
2613
return [('trees', self.last_revision())]
2615
2515
def lock_tree_write(self):
2616
2516
"""See WorkingTree.lock_tree_write().
2664
2564
def _change_last_revision(self, revision_id):
2665
2565
"""See WorkingTree._change_last_revision."""
2666
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2566
if revision_id is None or revision_id == NULL_REVISION:
2668
2568
self._transport.delete('last-revision')
2669
2569
except errors.NoSuchFile:
2673
2573
self._transport.put_bytes('last-revision', revision_id,
2674
mode=self.bzrdir._get_file_mode())
2574
mode=self._control_files._file_mode)
2677
def _get_check_refs(self):
2678
"""Return the references needed to perform a check of this tree."""
2679
return [('trees', self.last_revision())]
2681
2577
@needs_tree_write_lock
2682
2578
def set_conflicts(self, conflicts):
2683
self._put_rio('conflicts', conflicts.to_stanzas(),
2579
self._put_rio('conflicts', conflicts.to_stanzas(),
2684
2580
CONFLICT_HEADER_1)
2686
2582
@needs_tree_write_lock
2697
2593
except errors.NoSuchFile:
2698
2594
return _mod_conflicts.ConflictList()
2701
if confile.next() != CONFLICT_HEADER_1 + '\n':
2702
raise errors.ConflictFormatError()
2703
except StopIteration:
2596
if confile.next() != CONFLICT_HEADER_1 + '\n':
2704
2597
raise errors.ConflictFormatError()
2705
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2598
except StopIteration:
2599
raise errors.ConflictFormatError()
2600
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2709
2602
def unlock(self):
2710
2603
# do non-implementation specific cleanup
2735
2628
* a format string,
2736
2629
* an open routine.
2738
Formats are placed in an dict by their format string for reference
2631
Formats are placed in an dict by their format string for reference
2739
2632
during workingtree opening. Its not required that these be instances, they
2740
can be classes themselves with class methods - it simply depends on
2633
can be classes themselves with class methods - it simply depends on
2741
2634
whether state is needed for a given format or not.
2743
2636
Once a format is deprecated, just deprecate the initialize and open
2744
methods on the format class. Do not deprecate the object, as the
2637
methods on the format class. Do not deprecate the object, as the
2745
2638
object will be created every time regardless.
2791
2684
"""Is this format supported?
2793
2686
Supported formats can be initialized and opened.
2794
Unsupported formats may not support initialization or committing or
2687
Unsupported formats may not support initialization or committing or
2795
2688
some other features depending on the reason for not being supported.
2799
def supports_content_filtering(self):
2800
"""True if this format supports content filtering."""
2803
def supports_views(self):
2804
"""True if this format supports stored views."""
2808
2693
def register_format(klass, format):
2809
2694
klass._formats[format.get_format_string()] = format
2934
2819
def _open_control_files(self, a_bzrdir):
2935
2820
transport = a_bzrdir.get_workingtree_transport(None)
2936
return LockableFiles(transport, self._lock_file_name,
2821
return LockableFiles(transport, self._lock_file_name,
2937
2822
self._lock_class)
2939
2824
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2940
2825
accelerator_tree=None, hardlink=False):
2941
2826
"""See WorkingTreeFormat.initialize().
2943
2828
:param revision_id: if supplied, create a working tree at a different
2944
2829
revision than the branch is at.
2945
2830
:param accelerator_tree: A tree which can be used for retrieving file
2956
2841
control_files.create_lock()
2957
2842
control_files.lock_write()
2958
2843
transport.put_bytes('format', self.get_format_string(),
2959
mode=a_bzrdir._get_file_mode())
2844
mode=control_files._file_mode)
2960
2845
if from_branch is not None:
2961
2846
branch = from_branch
2982
2867
# only set an explicit root id if there is one to set.
2983
2868
if basis_tree.inventory.root is not None:
2984
2869
wt.set_root_id(basis_tree.get_root_id())
2985
if revision_id == _mod_revision.NULL_REVISION:
2870
if revision_id == NULL_REVISION:
2986
2871
wt.set_parent_trees([])
2988
2873
wt.set_parent_trees([(revision_id, basis_tree)])
3033
2918
__default_format = WorkingTreeFormat4()
3034
2919
WorkingTreeFormat.register_format(__default_format)
3035
WorkingTreeFormat.register_format(WorkingTreeFormat6())
3036
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3037
2920
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3038
2921
WorkingTreeFormat.set_default_format(__default_format)
3039
2922
# formats which have no format string are not discoverable