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
51
59
conflicts as _mod_conflicts,
61
67
revision as _mod_revision,
71
from bzrlib.workingtree_4 import (
80
from bzrlib.transport import get_transport
82
from bzrlib.workingtree_4 import WorkingTreeFormat4
78
85
from bzrlib import symbol_versioning
79
86
from bzrlib.decorators import needs_read_lock, needs_write_lock
80
from bzrlib.lock import LogicalLockResult
81
from bzrlib.lockable_files import LockableFiles
87
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
88
from bzrlib.lockable_files import LockableFiles, TransportLock
82
89
from bzrlib.lockdir import LockDir
83
90
import bzrlib.mutabletree
84
91
from bzrlib.mutabletree import needs_tree_write_lock
85
92
from bzrlib import osutils
86
93
from bzrlib.osutils import (
94
103
supports_executable,
96
from bzrlib.filters import filtered_input_file
97
105
from bzrlib.trace import mutter, note
98
106
from bzrlib.transport.local import LocalTransport
99
from bzrlib.revision import CURRENT_REVISION
107
from bzrlib.progress import DummyProgress, ProgressPhase
108
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
100
109
from bzrlib.rio import RioReader, rio_file, Stanza
101
from bzrlib.symbol_versioning import (
103
DEPRECATED_PARAMETER,
110
from bzrlib.symbol_versioning import (deprecated_passed,
113
DEPRECATED_PARAMETER,
107
120
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
108
# TODO: Modifying the conflict objects or their type is currently nearly
109
# impossible as there is no clear relationship between the working tree format
110
# and the conflict list file format.
111
121
CONFLICT_HEADER_1 = "BZR conflict list format 1"
113
123
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
126
@deprecated_function(zero_thirteen)
127
def gen_file_id(name):
128
"""Return new file id for the basename 'name'.
130
Use bzrlib.generate_ids.gen_file_id() instead
132
return generate_ids.gen_file_id(name)
135
@deprecated_function(zero_thirteen)
137
"""Return a new tree-root file id.
139
This has been deprecated in favor of bzrlib.generate_ids.gen_root_id()
141
return generate_ids.gen_root_id()
116
144
class TreeEntry(object):
117
145
"""An entry that implements the minimum interface used by commands.
119
This needs further inspection, it may be better to have
147
This needs further inspection, it may be better to have
120
148
InventoryEntries without ids - though that seems wrong. For now,
121
149
this is a parallel hierarchy to InventoryEntry, and needs to become
122
150
one of several things: decorates to that hierarchy, children of, or
210
232
self._branch = self.bzrdir.open_branch()
211
233
self.basedir = realpath(basedir)
212
self._control_files = _control_files
213
self._transport = self._control_files._transport
234
# if branch is at our basedir and is a format 6 or less
235
if isinstance(self._format, WorkingTreeFormat2):
236
# share control object
237
self._control_files = self.branch.control_files
239
# assume all other formats have their own control files.
240
assert isinstance(_control_files, LockableFiles), \
241
"_control_files must be a LockableFiles, not %r" \
243
self._control_files = _control_files
214
244
# update the whole cache up front and write to disk if anything changed;
215
245
# in the future we might want to do this more selectively
216
246
# two possible ways offer themselves : in self._unlock, write the cache
242
271
# permitted to do this.
243
272
self._set_inventory(_inventory, dirty=False)
244
273
self._detect_case_handling()
245
self._rules_searcher = None
246
self.views = self._make_views()
249
def user_transport(self):
250
return self.bzrdir.user_transport
253
def control_transport(self):
254
return self._transport
256
275
def _detect_case_handling(self):
257
276
wt_trans = self.bzrdir.get_workingtree_transport(None)
259
wt_trans.stat(self._format.case_sensitive_filename)
278
wt_trans.stat("FoRMaT")
260
279
except errors.NoSuchFile:
261
280
self.case_sensitive = True
263
282
self.case_sensitive = False
265
self._setup_directory_is_tree_reference()
267
284
branch = property(
268
285
fget=lambda self: self._branch,
269
286
doc="""The branch this WorkingTree is connected to.
283
300
self._control_files.break_lock()
284
301
self.branch.break_lock()
286
def _get_check_refs(self):
287
"""Return the references needed to perform a check of this tree.
289
The default implementation returns no refs, and is only suitable for
290
trees that have no local caching and can commit on ghosts at any time.
292
:seealso: bzrlib.check for details about check_refs.
296
303
def requires_rich_root(self):
297
304
return self._format.requires_rich_root
299
306
def supports_tree_reference(self):
302
def supports_content_filtering(self):
303
return self._format.supports_content_filtering()
305
def supports_views(self):
306
return self.views.supports_views()
308
309
def _set_inventory(self, inv, dirty):
309
310
"""Set the internal cached inventory.
345
347
path = osutils.getcwd()
346
348
control, relpath = bzrdir.BzrDir.open_containing(path)
347
350
return control.open_workingtree(), relpath
350
def open_containing_paths(file_list, default_directory=None,
351
canonicalize=True, apply_view=True):
352
"""Open the WorkingTree that contains a set of paths.
354
Fail if the paths given are not all in a single tree.
356
This is used for the many command-line interfaces that take a list of
357
any number of files and that require they all be in the same tree.
359
if default_directory is None:
360
default_directory = u'.'
361
# recommended replacement for builtins.internal_tree_files
362
if file_list is None or len(file_list) == 0:
363
tree = WorkingTree.open_containing(default_directory)[0]
364
# XXX: doesn't really belong here, and seems to have the strange
365
# side effect of making it return a bunch of files, not the whole
366
# tree -- mbp 20100716
367
if tree.supports_views() and apply_view:
368
view_files = tree.views.lookup_view()
370
file_list = view_files
371
view_str = views.view_display_str(view_files)
372
note("Ignoring files outside view. View is %s" % view_str)
373
return tree, file_list
374
if default_directory == u'.':
377
seed = default_directory
378
file_list = [osutils.pathjoin(default_directory, f)
380
tree = WorkingTree.open_containing(seed)[0]
381
return tree, tree.safe_relpath_files(file_list, canonicalize,
382
apply_view=apply_view)
384
def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
385
"""Convert file_list into a list of relpaths in tree.
387
:param self: A tree to operate on.
388
:param file_list: A list of user provided paths or None.
389
:param apply_view: if True and a view is set, apply it or check that
390
specified files are within it
391
:return: A list of relative paths.
392
:raises errors.PathNotChild: When a provided path is in a different self
395
if file_list is None:
397
if self.supports_views() and apply_view:
398
view_files = self.views.lookup_view()
402
# self.relpath exists as a "thunk" to osutils, but canonical_relpath
403
# doesn't - fix that up here before we enter the loop.
405
fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
408
for filename in file_list:
409
relpath = fixer(osutils.dereference_path(filename))
410
if view_files and not osutils.is_inside_any(view_files, relpath):
411
raise errors.FileOutsideView(filename, view_files)
412
new_list.append(relpath)
416
353
def open_downlevel(path=None):
417
354
"""Open an unsupported working tree.
485
400
# at this point ?
487
402
return self.branch.repository.revision_tree(revision_id)
488
except (errors.RevisionNotPresent, errors.NoSuchRevision):
403
except errors.RevisionNotPresent:
489
404
# the basis tree *may* be a ghost or a low level error may have
490
# occurred. If the revision is present, its a problem, if its not
405
# occured. If the revision is present, its a problem, if its not
492
407
if self.branch.repository.has_revision(revision_id):
494
409
# the basis tree is a ghost so return an empty tree.
495
return self.branch.repository.revision_tree(
496
_mod_revision.NULL_REVISION)
410
return self.branch.repository.revision_tree(None)
498
412
def _cleanup(self):
499
413
self._flush_ignore_list_cache()
416
@deprecated_method(zero_eight)
417
def create(branch, directory):
418
"""Create a workingtree for branch at directory.
420
If existing_directory already exists it must have a .bzr directory.
421
If it does not exist, it will be created.
423
This returns a new WorkingTree object for the new checkout.
425
TODO FIXME RBC 20060124 when we have checkout formats in place this
426
should accept an optional revisionid to checkout [and reject this if
427
checking out into the same dir as a pre-checkout-aware branch format.]
429
XXX: When BzrDir is present, these should be created through that
432
warnings.warn('delete WorkingTree.create', stacklevel=3)
433
transport = get_transport(directory)
434
if branch.bzrdir.root_transport.base == transport.base:
436
return branch.bzrdir.create_workingtree()
437
# different directory,
438
# create a branch reference
439
# and now a working tree.
440
raise NotImplementedError
443
@deprecated_method(zero_eight)
444
def create_standalone(directory):
445
"""Create a checkout and a branch and a repo at directory.
447
Directory must exist and be empty.
449
please use BzrDir.create_standalone_workingtree
451
return bzrdir.BzrDir.create_standalone_workingtree(directory)
501
453
def relpath(self, path):
502
454
"""Return the local path portion from a given path.
504
The path may be absolute or relative. If its a relative path it is
456
The path may be absolute or relative. If its a relative path it is
505
457
interpreted relative to the python current working directory.
507
459
return osutils.relpath(self.basedir, path)
509
461
def has_filename(self, filename):
510
462
return osutils.lexists(self.abspath(filename))
512
def get_file(self, file_id, path=None, filtered=True):
513
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
515
def get_file_with_stat(self, file_id, path=None, filtered=True,
517
"""See Tree.get_file_with_stat."""
464
def get_file(self, file_id, path=None):
519
466
path = self.id2path(file_id)
520
file_obj = self.get_file_byname(path, filtered=False)
521
stat_value = _fstat(file_obj.fileno())
522
if filtered and self.supports_content_filtering():
523
filters = self._content_filter_stack(path)
524
file_obj = filtered_input_file(file_obj, filters)
525
return (file_obj, stat_value)
527
def get_file_text(self, file_id, path=None, filtered=True):
528
my_file = self.get_file(file_id, path=path, filtered=filtered)
530
return my_file.read()
534
def get_file_byname(self, filename, filtered=True):
535
path = self.abspath(filename)
537
if filtered and self.supports_content_filtering():
538
filters = self._content_filter_stack(filename)
539
return filtered_input_file(f, filters)
543
def get_file_lines(self, file_id, path=None, filtered=True):
544
"""See Tree.get_file_lines()"""
545
file = self.get_file(file_id, path, filtered=filtered)
547
return file.readlines()
467
return self.get_file_byname(path)
469
def get_file_text(self, file_id):
470
return self.get_file(file_id).read()
472
def get_file_byname(self, filename):
473
return file(self.abspath(filename), 'rb')
552
476
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
559
483
incorrectly attributed to CURRENT_REVISION (but after committing, the
560
484
attribution will be correct).
562
maybe_file_parent_keys = []
563
for parent_id in self.get_parent_ids():
565
parent_tree = self.revision_tree(parent_id)
566
except errors.NoSuchRevisionInTree:
567
parent_tree = self.branch.repository.revision_tree(parent_id)
568
parent_tree.lock_read()
570
if file_id not in parent_tree:
572
ie = parent_tree.inventory[file_id]
573
if ie.kind != 'file':
574
# Note: this is slightly unnecessary, because symlinks and
575
# directories have a "text" which is the empty text, and we
576
# know that won't mess up annotations. But it seems cleaner
578
parent_text_key = (file_id, ie.revision)
579
if parent_text_key not in maybe_file_parent_keys:
580
maybe_file_parent_keys.append(parent_text_key)
583
graph = _mod_graph.Graph(self.branch.repository.texts)
584
heads = graph.heads(maybe_file_parent_keys)
585
file_parent_keys = []
586
for key in maybe_file_parent_keys:
588
file_parent_keys.append(key)
590
# Now we have the parents of this content
591
annotator = self.branch.repository.texts.get_annotator()
592
text = self.get_file_text(file_id)
593
this_key =(file_id, default_revision)
594
annotator.add_special_text(this_key, file_parent_keys, text)
595
annotations = [(key[-1], line)
596
for key, line in annotator.annotate_flat(this_key)]
486
basis = self.basis_tree()
489
changes = self._iter_changes(basis, True, [self.id2path(file_id)],
490
require_versioned=True).next()
491
changed_content, kind = changes[2], changes[6]
492
if not changed_content:
493
return basis.annotate_iter(file_id)
497
if kind[0] != 'file':
500
old_lines = list(basis.annotate_iter(file_id))
502
for tree in self.branch.repository.revision_trees(
503
self.get_parent_ids()[1:]):
504
if file_id not in tree:
506
old.append(list(tree.annotate_iter(file_id)))
507
return annotate.reannotate(old, self.get_file(file_id).readlines(),
599
512
def _get_ancestors(self, default_revision):
600
513
ancestors = set([default_revision])
637
550
def clone(self, to_bzrdir, revision_id=None):
638
551
"""Duplicate this working tree into to_bzr, including all state.
640
553
Specifically modified files are kept as modified, but
641
554
ignored and unknown files are discarded.
643
556
If you want to make a new line of development, see bzrdir.sprout()
646
If not None, the cloned tree will have its last revision set to
647
revision, and difference between the source trees last revision
559
If not None, the cloned tree will have its last revision set to
560
revision, and and difference between the source trees last revision
648
561
and this one merged in.
650
563
# assumes the target bzr dir format is compatible.
651
result = to_bzrdir.create_workingtree()
564
result = self._format.initialize(to_bzrdir)
652
565
self.copy_content_into(result, revision_id)
834
739
kind = 'tree-reference'
835
740
return kind, None, None, None
836
741
elif kind == 'symlink':
837
target = osutils.readlink(abspath)
838
return ('symlink', None, None, target)
742
return ('symlink', None, None, os.readlink(abspath))
840
744
return (kind, None, None, None)
842
def _file_content_summary(self, path, stat_result):
843
size = stat_result.st_size
844
executable = self._is_executable_from_path_and_stat(path, stat_result)
845
# try for a stat cache lookup
846
return ('file', size, executable, self._sha_from_stat(
746
@deprecated_method(zero_eleven)
748
def pending_merges(self):
749
"""Return a list of pending merges.
751
These are revisions that have been merged into the working
752
directory but not yet committed.
754
As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
755
instead - which is available on all tree objects.
757
return self.get_parent_ids()[1:]
849
759
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
850
760
"""Common ghost checking functionality from set_parent_*.
861
771
def _set_merges_from_parent_ids(self, parent_ids):
862
772
merges = parent_ids[1:]
863
self._transport.put_bytes('pending-merges', '\n'.join(merges),
864
mode=self.bzrdir._get_file_mode())
866
def _filter_parent_ids_by_ancestry(self, revision_ids):
867
"""Check that all merged revisions are proper 'heads'.
869
This will always return the first revision_id, and any merged revisions
872
if len(revision_ids) == 0:
874
graph = self.branch.repository.get_graph()
875
heads = graph.heads(revision_ids)
876
new_revision_ids = revision_ids[:1]
877
for revision_id in revision_ids[1:]:
878
if revision_id in heads and revision_id not in new_revision_ids:
879
new_revision_ids.append(revision_id)
880
if new_revision_ids != revision_ids:
881
trace.mutter('requested to set revision_ids = %s,'
882
' but filtered to %s', revision_ids, new_revision_ids)
883
return new_revision_ids
773
self._control_files.put_bytes('pending-merges', '\n'.join(merges))
885
775
@needs_tree_write_lock
886
776
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
887
777
"""Set the parent ids to revision_ids.
889
779
See also set_parent_trees. This api will try to retrieve the tree data
890
780
for each element of revision_ids from the trees repository. If you have
891
781
tree data already available, it is more efficient to use
981
866
branch.last_revision().
983
868
from bzrlib.merge import Merger, Merge3Merger
984
merger = Merger(self.branch, this_tree=self)
985
# check that there are no local alterations
986
if not force and self.has_changes():
987
raise errors.UncommittedChanges(self)
988
if to_revision is None:
989
to_revision = _mod_revision.ensure_null(branch.last_revision())
990
merger.other_rev_id = to_revision
991
if _mod_revision.is_null(merger.other_rev_id):
992
raise errors.NoCommits(branch)
993
self.branch.fetch(branch, last_revision=merger.other_rev_id)
994
merger.other_basis = merger.other_rev_id
995
merger.other_tree = self.branch.repository.revision_tree(
997
merger.other_branch = branch
998
if from_revision is None:
1001
merger.set_base_revision(from_revision, branch)
1002
if merger.base_rev_id == merger.other_rev_id:
1003
raise errors.PointlessMerge
1004
merger.backup_files = False
1005
if merge_type is None:
1006
merger.merge_type = Merge3Merger
1008
merger.merge_type = merge_type
1009
merger.set_interesting_files(None)
1010
merger.show_base = False
1011
merger.reprocess = False
1012
conflicts = merger.do_merge()
1013
merger.set_pending()
869
pb = bzrlib.ui.ui_factory.nested_progress_bar()
871
merger = Merger(self.branch, this_tree=self, pb=pb)
872
merger.pp = ProgressPhase("Merge phase", 5, pb)
873
merger.pp.next_phase()
874
# check that there are no
876
merger.check_basis(check_clean=True, require_commits=False)
877
if to_revision is None:
878
to_revision = _mod_revision.ensure_null(branch.last_revision())
879
merger.other_rev_id = to_revision
880
if _mod_revision.is_null(merger.other_rev_id):
881
raise errors.NoCommits(branch)
882
self.branch.fetch(branch, last_revision=merger.other_rev_id)
883
merger.other_basis = merger.other_rev_id
884
merger.other_tree = self.branch.repository.revision_tree(
886
merger.other_branch = branch
887
merger.pp.next_phase()
888
if from_revision is None:
891
merger.set_base_revision(from_revision, branch)
892
if merger.base_rev_id == merger.other_rev_id:
893
raise errors.PointlessMerge
894
merger.backup_files = False
895
if merge_type is None:
896
merger.merge_type = Merge3Merger
898
merger.merge_type = merge_type
899
merger.set_interesting_files(None)
900
merger.show_base = False
901
merger.reprocess = False
902
conflicts = merger.do_merge()
1014
906
return conflicts
1016
908
@needs_read_lock
1017
909
def merge_modified(self):
1018
910
"""Return a dictionary of files modified by a merge.
1020
The list is initialized by WorkingTree.set_merge_modified, which is
912
The list is initialized by WorkingTree.set_merge_modified, which is
1021
913
typically called after we make some automatic updates to the tree
1022
914
because of a merge.
1025
917
still in the working inventory and have that text hash.
1028
hashfile = self._transport.get('merge-hashes')
920
hashfile = self._control_files.get('merge-hashes')
1029
921
except errors.NoSuchFile:
1034
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
1035
raise errors.MergeModifiedFormatError()
1036
except StopIteration:
925
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
1037
926
raise errors.MergeModifiedFormatError()
1038
for s in RioReader(hashfile):
1039
# RioReader reads in Unicode, so convert file_ids back to utf8
1040
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
1041
if file_id not in self.inventory:
1043
text_hash = s.get("hash")
1044
if text_hash == self.get_file_sha1(file_id):
1045
merge_hashes[file_id] = text_hash
927
except StopIteration:
928
raise errors.MergeModifiedFormatError()
929
for s in RioReader(hashfile):
930
# RioReader reads in Unicode, so convert file_ids back to utf8
931
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
932
if file_id not in self.inventory:
934
text_hash = s.get("hash")
935
if text_hash == self.get_file_sha1(file_id):
936
merge_hashes[file_id] = text_hash
1050
939
@needs_write_lock
1051
940
def mkdir(self, path, file_id=None):
1103
990
other_tree.unlock()
1104
991
other_tree.bzrdir.retire_bzrdir()
1106
def _setup_directory_is_tree_reference(self):
1107
if self._branch.repository._format.supports_tree_reference:
1108
self._directory_is_tree_reference = \
1109
self._directory_may_be_tree_reference
1111
self._directory_is_tree_reference = \
1112
self._directory_is_never_tree_reference
1114
def _directory_is_never_tree_reference(self, relpath):
1117
def _directory_may_be_tree_reference(self, relpath):
1118
# as a special case, if a directory contains control files then
993
def _directory_is_tree_reference(self, relpath):
994
# as a special case, if a directory contains control files then
1119
995
# it's a tree reference, except that the root of the tree is not
1120
996
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1121
997
# TODO: We could ask all the control formats whether they
1143
1019
transport = transport.clone(name)
1144
1020
transport.ensure_base()
1145
1021
return transport
1147
1023
sub_path = self.id2path(file_id)
1148
1024
branch_transport = mkdirs(sub_path)
1149
1025
if format is None:
1150
format = self.bzrdir.cloning_metadir()
1026
format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
1151
1027
branch_transport.ensure_base()
1152
1028
branch_bzrdir = format.initialize_on_transport(branch_transport)
1154
1030
repo = branch_bzrdir.find_repository()
1155
1031
except errors.NoRepositoryPresent:
1156
1032
repo = branch_bzrdir.create_repository()
1157
if not repo.supports_rich_root():
1158
raise errors.RootNotRich()
1033
assert repo.supports_rich_root()
1035
if not repo.supports_rich_root():
1036
raise errors.RootNotRich()
1159
1037
new_branch = branch_bzrdir.create_branch()
1160
1038
new_branch.pull(self.branch)
1161
1039
for parent_id in self.get_parent_ids():
1163
1041
tree_transport = self.bzrdir.root_transport.clone(sub_path)
1164
1042
if tree_transport.base != branch_transport.base:
1165
1043
tree_bzrdir = format.initialize_on_transport(tree_transport)
1166
branch.BranchReferenceFormat().initialize(tree_bzrdir,
1167
target_branch=new_branch)
1044
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1169
1046
tree_bzrdir = branch_bzrdir
1170
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1047
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1171
1048
wt.set_parent_ids(self.get_parent_ids())
1172
1049
my_inv = self.inventory
1173
child_inv = inventory.Inventory(root_id=None)
1050
child_inv = Inventory(root_id=None)
1174
1051
new_root = my_inv[file_id]
1175
1052
my_inv.remove_recursive_id(file_id)
1176
1053
new_root.parent_id = None
1194
1071
sio = StringIO()
1195
1072
self._serialize(self._inventory, sio)
1197
self._transport.put_file('inventory', sio,
1198
mode=self.bzrdir._get_file_mode())
1074
self._control_files.put('inventory', sio)
1199
1075
self._inventory_is_modified = False
1201
1077
def _kind(self, relpath):
1202
1078
return osutils.file_kind(self.abspath(relpath))
1204
def list_files(self, include_root=False, from_dir=None, recursive=True):
1205
"""List all files as (path, class, kind, id, entry).
1080
def list_files(self, include_root=False):
1081
"""Recursively list all files as (path, class, kind, id, entry).
1207
1083
Lists, but does not descend into unversioned directories.
1208
1085
This does not include files that have been deleted in this
1209
tree. Skips the control directory.
1211
:param include_root: if True, return an entry for the root
1212
:param from_dir: start from this directory or None for the root
1213
:param recursive: whether to recurse into subdirectories or not
1088
Skips the control directory.
1215
1090
# list_files is an iterator, so @needs_read_lock doesn't work properly
1216
1091
# with it. So callers should be careful to always read_lock the tree.
1231
1106
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1233
1108
# directory file_id, relative path, absolute path, reverse sorted children
1234
if from_dir is not None:
1235
from_dir_id = inv.path2id(from_dir)
1236
if from_dir_id is None:
1237
# Directory not versioned
1239
from_dir_abspath = pathjoin(self.basedir, from_dir)
1241
from_dir_id = inv.root.file_id
1242
from_dir_abspath = self.basedir
1243
children = os.listdir(from_dir_abspath)
1109
children = os.listdir(self.basedir)
1244
1110
children.sort()
1245
# jam 20060527 The kernel sized tree seems equivalent whether we
1111
# jam 20060527 The kernel sized tree seems equivalent whether we
1246
1112
# use a deque and popleft to keep them sorted, or if we use a plain
1247
1113
# list and just reverse() them.
1248
1114
children = collections.deque(children)
1249
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1115
stack = [(inv.root.file_id, u'', self.basedir, children)]
1251
1117
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1311
1172
except KeyError:
1312
1173
yield fp[1:], c, fk, None, TreeEntry()
1315
1176
if fk != 'directory':
1318
# But do this child first if recursing down
1320
new_children = os.listdir(fap)
1322
new_children = collections.deque(new_children)
1323
stack.append((f_ie.file_id, fp, fap, new_children))
1324
# Break out of inner loop,
1325
# so that we start outer loop with child
1179
# But do this child first
1180
new_children = os.listdir(fap)
1182
new_children = collections.deque(new_children)
1183
stack.append((f_ie.file_id, fp, fap, new_children))
1184
# Break out of inner loop,
1185
# so that we start outer loop with child
1328
1188
# if we finished all children, pop it off the stack
1331
1191
@needs_tree_write_lock
1332
def move(self, from_paths, to_dir=None, after=False):
1192
def move(self, from_paths, to_dir=None, after=False, **kwargs):
1333
1193
"""Rename files.
1335
1195
to_dir must exist in the inventory.
1337
1197
If to_dir exists and is a directory, the files are moved into
1338
it, keeping their old names.
1198
it, keeping their old names.
1340
1200
Note that to_dir is only the last component of the new name;
1341
1201
this doesn't change the directory.
1445
1311
# check the inventory for source and destination
1446
1312
if from_id is None:
1447
1313
raise errors.BzrMoveFailedError(from_rel,to_rel,
1448
errors.NotVersionedError(path=from_rel))
1314
errors.NotVersionedError(path=str(from_rel)))
1449
1315
if to_id is not None:
1450
1316
raise errors.BzrMoveFailedError(from_rel,to_rel,
1451
errors.AlreadyVersionedError(path=to_rel))
1317
errors.AlreadyVersionedError(path=str(to_rel)))
1453
1319
# try to determine the mode for rename (only change inv or change
1454
1320
# inv and file system)
1456
1322
if not self.has_filename(to_rel):
1457
1323
raise errors.BzrMoveFailedError(from_id,to_rel,
1458
errors.NoSuchFile(path=to_rel,
1324
errors.NoSuchFile(path=str(to_rel),
1459
1325
extra="New file has not been created yet"))
1460
1326
only_change_inv = True
1461
1327
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1462
1328
only_change_inv = True
1463
1329
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1464
1330
only_change_inv = False
1465
elif (not self.case_sensitive
1466
and from_rel.lower() == to_rel.lower()
1467
and self.has_filename(from_rel)):
1331
elif (sys.platform == 'win32'
1332
and from_rel.lower() == to_rel.lower()
1333
and self.has_filename(from_rel)):
1468
1334
only_change_inv = False
1470
1336
# something is wrong, so lets determine what exactly
1558
1423
from_tail = splitpath(from_rel)[-1]
1559
1424
from_id = inv.path2id(from_rel)
1560
1425
if from_id is None:
1561
# if file is missing in the inventory maybe it's in the basis_tree
1562
basis_tree = self.branch.basis_tree()
1563
from_id = basis_tree.path2id(from_rel)
1565
raise errors.BzrRenameFailedError(from_rel,to_rel,
1566
errors.NotVersionedError(path=from_rel))
1567
# put entry back in the inventory so we can rename it
1568
from_entry = basis_tree.inventory[from_id].copy()
1571
from_entry = inv[from_id]
1426
raise errors.BzrRenameFailedError(from_rel,to_rel,
1427
errors.NotVersionedError(path=str(from_rel)))
1428
from_entry = inv[from_id]
1572
1429
from_parent_id = from_entry.parent_id
1573
1430
to_dir, to_tail = os.path.split(to_rel)
1574
1431
to_dir_id = inv.path2id(to_dir)
1636
1493
:raises: NoSuchId if any fileid is not currently versioned.
1638
1495
for file_id in file_ids:
1639
if file_id not in self._inventory:
1640
raise errors.NoSuchId(self, file_id)
1641
for file_id in file_ids:
1642
1496
if self._inventory.has_id(file_id):
1643
1497
self._inventory.remove_recursive_id(file_id)
1499
raise errors.NoSuchId(self, file_id)
1644
1500
if len(file_ids):
1645
# in the future this should just set a dirty bit to wait for the
1501
# in the future this should just set a dirty bit to wait for the
1646
1502
# final unlock. However, until all methods of workingtree start
1647
# with the current in -memory inventory rather than triggering
1503
# with the current in -memory inventory rather than triggering
1648
1504
# a read, it is more complex - we need to teach read_inventory
1649
1505
# to know when to read, and when to not read first... and possibly
1650
1506
# to save first when the in memory one may be corrupted.
1651
1507
# so for now, we just only write it if it is indeed dirty.
1652
1508
# - RBC 20060907
1653
1509
self._write_inventory(self._inventory)
1511
@deprecated_method(zero_eight)
1512
def iter_conflicts(self):
1513
"""List all files in the tree that have text or content conflicts.
1514
DEPRECATED. Use conflicts instead."""
1515
return self._iter_conflicts()
1655
1517
def _iter_conflicts(self):
1656
1518
conflicted = set()
1666
1528
@needs_write_lock
1667
1529
def pull(self, source, overwrite=False, stop_revision=None,
1668
change_reporter=None, possible_transports=None, local=False,
1530
change_reporter=None, possible_transports=None):
1531
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1670
1532
source.lock_read()
1534
pp = ProgressPhase("Pull phase", 2, top_pb)
1672
1536
old_revision_info = self.branch.last_revision_info()
1673
1537
basis_tree = self.basis_tree()
1674
1538
count = self.branch.pull(source, overwrite, stop_revision,
1675
possible_transports=possible_transports,
1539
possible_transports=possible_transports)
1677
1540
new_revision_info = self.branch.last_revision_info()
1678
1541
if new_revision_info != old_revision_info:
1679
1543
repository = self.branch.repository
1544
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1680
1545
basis_tree.lock_read()
1682
1547
new_basis_tree = self.branch.basis_tree()
1685
1550
new_basis_tree,
1687
1552
this_tree=self,
1689
change_reporter=change_reporter,
1690
show_base=show_base)
1691
basis_root_id = basis_tree.get_root_id()
1692
new_root_id = new_basis_tree.get_root_id()
1693
if basis_root_id != new_root_id:
1694
self.set_root_id(new_root_id)
1554
change_reporter=change_reporter)
1555
if (basis_tree.inventory.root is None and
1556
new_basis_tree.inventory.root is not None):
1557
self.set_root_id(new_basis_tree.get_root_id())
1696
1560
basis_tree.unlock()
1697
1561
# TODO - dedup parents list with things merged by pull ?
1698
1562
# reuse the revisiontree we merged against to set the new
1700
1564
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1701
# we have to pull the merge trees out again, because
1702
# merge_inner has set the ids. - this corner is not yet
1565
# we have to pull the merge trees out again, because
1566
# merge_inner has set the ids. - this corner is not yet
1703
1567
# layered well enough to prevent double handling.
1704
1568
# XXX TODO: Fix the double handling: telling the tree about
1705
1569
# the already known parent data is wasteful.
1801
1659
r"""Check whether the filename matches an ignore pattern.
1803
1661
Patterns containing '/' or '\' need to match the whole path;
1804
others match against only the last component. Patterns starting
1805
with '!' are ignore exceptions. Exceptions take precedence
1806
over regular patterns and cause the filename to not be ignored.
1662
others match against only the last component.
1808
1664
If the file is ignored, returns the pattern which caused it to
1809
1665
be ignored, otherwise None. So this can simply be used as a
1810
1666
boolean if desired."""
1811
1667
if getattr(self, '_ignoreglobster', None) is None:
1812
self._ignoreglobster = globbing.ExceptionGlobster(self.get_ignore_list())
1668
self._ignoreglobster = globbing.Globster(self.get_ignore_list())
1813
1669
return self._ignoreglobster.match(filename)
1815
1671
def kind(self, file_id):
1816
1672
return file_kind(self.id2abspath(file_id))
1818
def stored_kind(self, file_id):
1819
"""See Tree.stored_kind"""
1820
return self.inventory[file_id].kind
1822
1674
def _comparison_data(self, entry, path):
1823
1675
abspath = self.abspath(path)
1865
1717
raise errors.ObjectNotLocked(self)
1867
1719
def lock_read(self):
1868
"""Lock the tree for reading.
1870
This also locks the branch, and can be unlocked via self.unlock().
1872
:return: A bzrlib.lock.LogicalLockResult.
1720
"""See Branch.lock_read, and WorkingTree.unlock."""
1874
1721
if not self.is_locked():
1875
1722
self._reset_data()
1876
1723
self.branch.lock_read()
1878
self._control_files.lock_read()
1879
return LogicalLockResult(self.unlock)
1725
return self._control_files.lock_read()
1881
1727
self.branch.unlock()
1884
1730
def lock_tree_write(self):
1885
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1887
:return: A bzrlib.lock.LogicalLockResult.
1731
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1889
1732
if not self.is_locked():
1890
1733
self._reset_data()
1891
1734
self.branch.lock_read()
1893
self._control_files.lock_write()
1894
return LogicalLockResult(self.unlock)
1736
return self._control_files.lock_write()
1896
1738
self.branch.unlock()
1899
1741
def lock_write(self):
1900
"""See MutableTree.lock_write, and WorkingTree.unlock.
1902
:return: A bzrlib.lock.LogicalLockResult.
1742
"""See MutableTree.lock_write, and WorkingTree.unlock."""
1904
1743
if not self.is_locked():
1905
1744
self._reset_data()
1906
1745
self.branch.lock_write()
1908
self._control_files.lock_write()
1909
return LogicalLockResult(self.unlock)
1747
return self._control_files.lock_write()
1911
1749
self.branch.unlock()
1967
1801
# as commit already has that ready-to-use [while the format is the
1968
1802
# same, that is].
1970
# this double handles the inventory - unpack and repack -
1804
# this double handles the inventory - unpack and repack -
1971
1805
# but is easier to understand. We can/should put a conditional
1972
1806
# in here based on whether the inventory is in the latest format
1973
1807
# - perhaps we should repack all inventories on a repository
1975
1809
# the fast path is to copy the raw xml from the repository. If the
1976
# xml contains 'revision_id="', then we assume the right
1810
# xml contains 'revision_id="', then we assume the right
1977
1811
# revision_id is set. We must check for this full string, because a
1978
1812
# root node id can legitimately look like 'revision_id' but cannot
1979
1813
# contain a '"'.
1980
xml = self.branch.repository._get_inventory_xml(new_revision)
1814
xml = self.branch.repository.get_inventory_xml(new_revision)
1981
1815
firstline = xml.split('\n', 1)[0]
1982
if (not 'revision_id="' in firstline or
1816
if (not 'revision_id="' in firstline or
1983
1817
'format="7"' not in firstline):
1984
inv = self.branch.repository._serializer.read_inventory_from_string(
1818
inv = self.branch.repository.deserialise_inventory(
1986
1820
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1987
1821
self._write_basis_inventory(xml)
1988
1822
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1991
1825
def read_basis_inventory(self):
1992
1826
"""Read the cached basis inventory."""
1993
1827
path = self._basis_inventory_name()
1994
return self._transport.get_bytes(path)
1828
return self._control_files.get(path).read()
1996
1830
@needs_read_lock
1997
1831
def read_working_inventory(self):
1998
1832
"""Read the working inventory.
2000
1834
:raises errors.InventoryModified: read_working_inventory will fail
2001
1835
when the current in memory inventory has been modified.
2003
# conceptually this should be an implementation detail of the tree.
1837
# conceptually this should be an implementation detail of the tree.
2004
1838
# XXX: Deprecate this.
2005
1839
# ElementTree does its own conversion from UTF-8, so open in
2007
1841
if self._inventory_is_modified:
2008
1842
raise errors.InventoryModified(self)
2009
f = self._transport.get('inventory')
2011
result = self._deserialize(f)
1843
result = self._deserialize(self._control_files.get('inventory'))
2014
1844
self._set_inventory(result, dirty=False)
2032
all_files = set() # specified and nested files
2033
1863
unknown_nested_files=set()
2035
to_file = sys.stdout
2037
files_to_backup = []
2039
1865
def recurse_directory_to_add_files(directory):
2040
1866
# Recurse directory and add all files
2041
1867
# so we can check if they have changed.
2042
for parent_info, file_infos in self.walkdirs(directory):
2043
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1868
for parent_info, file_infos in\
1869
osutils.walkdirs(self.abspath(directory),
1871
for relpath, basename, kind, lstat, abspath in file_infos:
2044
1872
# Is it versioned or ignored?
2045
if self.path2id(relpath):
1873
if self.path2id(relpath) or self.is_ignored(relpath):
2046
1874
# Add nested content for deletion.
2047
all_files.add(relpath)
1875
new_files.add(relpath)
2049
# Files which are not versioned
1877
# Files which are not versioned and not ignored
2050
1878
# should be treated as unknown.
2051
files_to_backup.append(relpath)
1879
unknown_nested_files.add((relpath, None, kind))
2053
1881
for filename in files:
2054
1882
# Get file name into canonical form.
2055
1883
abspath = self.abspath(filename)
2056
1884
filename = self.relpath(abspath)
2057
1885
if len(filename) > 0:
2058
all_files.add(filename)
2059
recurse_directory_to_add_files(filename)
1886
new_files.add(filename)
1887
if osutils.isdir(abspath):
1888
recurse_directory_to_add_files(filename)
2061
files = list(all_files)
1890
files = list(new_files)
2063
1892
if len(files) == 0:
2064
1893
return # nothing to do
2069
1898
# Bail out if we are going to delete files we shouldn't
2070
1899
if not keep_files and not force:
2071
for (file_id, path, content_change, versioned, parent_id, name,
2072
kind, executable) in self.iter_changes(self.basis_tree(),
2073
include_unchanged=True, require_versioned=False,
2074
want_unversioned=True, specific_files=files):
2075
if versioned[0] == False:
2076
# The record is unknown or newly added
2077
files_to_backup.append(path[1])
2078
elif (content_change and (kind[1] is not None) and
2079
osutils.is_inside_any(files, path[1])):
2080
# Versioned and changed, but not deleted, and still
2081
# in one of the dirs to be deleted.
2082
files_to_backup.append(path[1])
2084
def backup(file_to_backup):
2085
backup_name = self.bzrdir._available_backup_name(file_to_backup)
2086
osutils.rename(abs_path, self.abspath(backup_name))
2087
return "removed %s (but kept a copy: %s)" % (file_to_backup,
2090
# Build inv_delta and delete files where applicable,
1900
has_changed_files = len(unknown_nested_files) > 0
1901
if not has_changed_files:
1902
for (file_id, path, content_change, versioned, parent_id, name,
1903
kind, executable) in self._iter_changes(self.basis_tree(),
1904
include_unchanged=True, require_versioned=False,
1905
want_unversioned=True, specific_files=files):
1906
if versioned == (False, False):
1907
# The record is unknown ...
1908
if not self.is_ignored(path[1]):
1909
# ... but not ignored
1910
has_changed_files = True
1912
elif content_change and (kind[1] != None):
1913
# Versioned and changed, but not deleted
1914
has_changed_files = True
1917
if has_changed_files:
1918
# Make delta show ALL applicable changes in error message.
1919
tree_delta = self.changes_from(self.basis_tree(),
1920
require_versioned=False, want_unversioned=True,
1921
specific_files=files)
1922
for unknown_file in unknown_nested_files:
1923
if unknown_file not in tree_delta.unversioned:
1924
tree_delta.unversioned.extend((unknown_file,))
1925
raise errors.BzrRemoveChangedFilesError(tree_delta)
1927
# Build inv_delta and delete files where applicaple,
2091
1928
# do this before any modifications to inventory.
2092
1929
for f in files:
2093
1930
fid = self.path2id(f)
2219
2053
@needs_tree_write_lock
2220
2054
def set_root_id(self, file_id):
2221
2055
"""Set the root id for this tree."""
2223
2057
if file_id is None:
2225
'WorkingTree.set_root_id with fileid=None')
2226
file_id = osutils.safe_file_id(file_id)
2058
symbol_versioning.warn(symbol_versioning.zero_twelve
2059
% 'WorkingTree.set_root_id with fileid=None',
2064
file_id = osutils.safe_file_id(file_id)
2227
2065
self._set_root_id(file_id)
2229
2067
def _set_root_id(self, file_id):
2230
2068
"""Set the root id for this tree, in a format specific manner.
2232
:param file_id: The file id to assign to the root. It must not be
2070
:param file_id: The file id to assign to the root. It must not be
2233
2071
present in the current inventory or an error will occur. It must
2234
2072
not be None, but rather a valid file id.
2255
2093
def unlock(self):
2256
2094
"""See Branch.unlock.
2258
2096
WorkingTree locking just uses the Branch locking facilities.
2259
2097
This is current because all working trees have an embedded branch
2260
2098
within them. IF in the future, we were to make branch data shareable
2261
between multiple working trees, i.e. via shared storage, then we
2099
between multiple working trees, i.e. via shared storage, then we
2262
2100
would probably want to lock both the local tree, and the branch.
2264
2102
raise NotImplementedError(self.unlock)
2268
def update(self, change_reporter=None, possible_transports=None,
2269
revision=None, old_tip=_marker, show_base=False):
2104
def update(self, change_reporter=None, possible_transports=None):
2270
2105
"""Update a working tree along its branch.
2272
2107
This will update the branch if its bound too, which means we have
2327
2154
# cant set that until we update the working trees last revision to be
2328
2155
# one from the new branch, because it will just get absorbed by the
2329
2156
# parent de-duplication logic.
2331
2158
# We MUST save it even if an error occurs, because otherwise the users
2332
2159
# local work is unreferenced and will appear to have been lost.
2336
2163
last_rev = self.get_parent_ids()[0]
2337
2164
except IndexError:
2338
2165
last_rev = _mod_revision.NULL_REVISION
2339
if revision is None:
2340
revision = self.branch.last_revision()
2342
old_tip = old_tip or _mod_revision.NULL_REVISION
2344
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
2345
# the branch we are bound to was updated
2346
# merge those changes in first
2347
base_tree = self.basis_tree()
2348
other_tree = self.branch.repository.revision_tree(old_tip)
2349
nb_conflicts = merge.merge_inner(self.branch, other_tree,
2350
base_tree, this_tree=self,
2351
change_reporter=change_reporter,
2352
show_base=show_base)
2354
self.add_parent_tree((old_tip, other_tree))
2355
trace.note('Rerun update after fixing the conflicts.')
2358
if last_rev != _mod_revision.ensure_null(revision):
2359
# the working tree is up to date with the branch
2360
# we can merge the specified revision from master
2361
to_tree = self.branch.repository.revision_tree(revision)
2362
to_root_id = to_tree.get_root_id()
2166
if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2167
# merge tree state up to new branch tip.
2364
2168
basis = self.basis_tree()
2365
2169
basis.lock_read()
2367
if (basis.inventory.root is None
2368
or basis.inventory.root.file_id != to_root_id):
2369
self.set_root_id(to_root_id)
2171
to_tree = self.branch.basis_tree()
2172
if basis.inventory.root is None:
2173
self.set_root_id(to_tree.get_root_id())
2175
result += merge.merge_inner(
2180
change_reporter=change_reporter)
2374
# determine the branch point
2375
graph = self.branch.repository.get_graph()
2376
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2378
base_tree = self.branch.repository.revision_tree(base_rev_id)
2380
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2382
change_reporter=change_reporter,
2383
show_base=show_base)
2384
self.set_last_revision(revision)
2385
2183
# TODO - dedup parents list with things merged by pull ?
2386
2184
# reuse the tree we've updated to to set the basis:
2387
parent_trees = [(revision, to_tree)]
2185
parent_trees = [(self.branch.last_revision(), to_tree)]
2388
2186
merges = self.get_parent_ids()[1:]
2389
2187
# Ideally we ask the tree for the trees here, that way the working
2390
# tree can decide whether to give us the entire tree or give us a
2188
# tree can decide whether to give us teh entire tree or give us a
2391
2189
# lazy initialised tree. dirstate for instance will have the trees
2392
2190
# in ram already, whereas a last-revision + basis-inventory tree
2393
2191
# will not, but also does not need them when setting parents.
2394
2192
for parent in merges:
2395
2193
parent_trees.append(
2396
2194
(parent, self.branch.repository.revision_tree(parent)))
2397
if not _mod_revision.is_null(old_tip):
2195
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2398
2196
parent_trees.append(
2399
2197
(old_tip, self.branch.repository.revision_tree(old_tip)))
2400
2198
self.set_parent_trees(parent_trees)
2401
2199
last_rev = parent_trees[0][0]
2201
# the working tree had the same last-revision as the master
2202
# branch did. We may still have pivot local work from the local
2203
# branch into old_tip:
2204
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2205
self.add_parent_tree_id(old_tip)
2206
if (old_tip is not None and not _mod_revision.is_null(old_tip)
2207
and old_tip != last_rev):
2208
# our last revision was not the prior branch last revision
2209
# and we have converted that last revision to a pending merge.
2210
# base is somewhere between the branch tip now
2211
# and the now pending merge
2213
# Since we just modified the working tree and inventory, flush out
2214
# the current state, before we modify it again.
2215
# TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2216
# requires it only because TreeTransform directly munges the
2217
# inventory and calls tree._write_inventory(). Ultimately we
2218
# should be able to remove this extra flush.
2220
graph = self.branch.repository.get_graph()
2221
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2223
base_tree = self.branch.repository.revision_tree(base_rev_id)
2224
other_tree = self.branch.repository.revision_tree(old_tip)
2225
result += merge.merge_inner(
2230
change_reporter=change_reporter)
2404
2233
def _write_hashcache_if_dirty(self):
2405
2234
"""Write out the hashcache if it is dirty."""
2603
2430
# FIXME: stash the node in pending
2604
2431
entry = inv[top_id]
2605
if entry.kind == 'directory':
2606
for name, child in entry.sorted_children():
2607
dirblock.append((relroot + name, name, child.kind, None,
2608
child.file_id, child.kind
2432
for name, child in entry.sorted_children():
2433
dirblock.append((relroot + name, name, child.kind, None,
2434
child.file_id, child.kind
2610
2436
yield (currentdir[0], entry.file_id), dirblock
2611
2437
# push the user specified dirs from dirblock
2612
2438
for dir in reversed(dirblock):
2679
def check_state(self):
2680
"""Check that the working state is/isn't valid."""
2681
check_refs = self._get_check_refs()
2683
for ref in check_refs:
2686
refs[ref] = self.branch.repository.revision_tree(value)
2689
@needs_tree_write_lock
2690
def reset_state(self, revision_ids=None):
2691
"""Reset the state of the working tree.
2693
This does a hard-reset to a last-known-good state. This is a way to
2694
fix if something got corrupted (like the .bzr/checkout/dirstate file)
2696
if revision_ids is None:
2697
revision_ids = self.get_parent_ids()
2698
if not revision_ids:
2699
rt = self.branch.repository.revision_tree(
2700
_mod_revision.NULL_REVISION)
2702
rt = self.branch.repository.revision_tree(revision_ids[0])
2703
self._write_inventory(rt.inventory)
2704
self.set_parent_ids(revision_ids)
2706
def _get_rules_searcher(self, default_searcher):
2707
"""See Tree._get_rules_searcher."""
2708
if self._rules_searcher is None:
2709
self._rules_searcher = super(WorkingTree,
2710
self)._get_rules_searcher(default_searcher)
2711
return self._rules_searcher
2713
def get_shelf_manager(self):
2714
"""Return the ShelfManager for this WorkingTree."""
2715
from bzrlib.shelf import ShelfManager
2716
return ShelfManager(self, self._transport)
2719
2486
class WorkingTree2(WorkingTree):
2720
2487
"""This is the Format 2 working tree.
2722
This was the first weave based working tree.
2489
This was the first weave based working tree.
2723
2490
- uses os locks for locking.
2724
2491
- uses the branch last-revision.
2788
2547
def _last_revision(self):
2789
2548
"""See Mutable.last_revision."""
2791
return self._transport.get_bytes('last-revision')
2550
return self._control_files.get('last-revision').read()
2792
2551
except errors.NoSuchFile:
2793
2552
return _mod_revision.NULL_REVISION
2795
2554
def _change_last_revision(self, revision_id):
2796
2555
"""See WorkingTree._change_last_revision."""
2797
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2556
if revision_id is None or revision_id == NULL_REVISION:
2799
self._transport.delete('last-revision')
2558
self._control_files._transport.delete('last-revision')
2800
2559
except errors.NoSuchFile:
2804
self._transport.put_bytes('last-revision', revision_id,
2805
mode=self.bzrdir._get_file_mode())
2563
self._control_files.put_bytes('last-revision', revision_id)
2808
def _get_check_refs(self):
2809
"""Return the references needed to perform a check of this tree."""
2810
return [('trees', self.last_revision())]
2812
2566
@needs_tree_write_lock
2813
2567
def set_conflicts(self, conflicts):
2814
self._put_rio('conflicts', conflicts.to_stanzas(),
2568
self._put_rio('conflicts', conflicts.to_stanzas(),
2815
2569
CONFLICT_HEADER_1)
2817
2571
@needs_tree_write_lock
2883
2650
"""The known formats."""
2886
"""Extra formats that can not be used in a metadir."""
2888
2652
requires_rich_root = False
2890
2654
upgrade_recommended = False
2892
requires_normalized_unicode_filenames = False
2894
case_sensitive_filename = "FoRMaT"
2896
missing_parent_conflicts = False
2897
"""If this format supports missing parent conflicts."""
2900
2657
def find_format(klass, a_bzrdir):
2901
2658
"""Return the format for the working tree object in a_bzrdir."""
2903
2660
transport = a_bzrdir.get_workingtree_transport(None)
2904
format_string = transport.get_bytes("format")
2661
format_string = transport.get("format").read()
2905
2662
return klass._formats[format_string]
2906
2663
except errors.NoSuchFile:
2907
2664
raise errors.NoWorkingTree(base=transport.base)
2908
2665
except KeyError:
2909
raise errors.UnknownFormatError(format=format_string,
2910
kind="working tree")
2666
raise errors.UnknownFormatError(format=format_string)
2912
2668
def __eq__(self, other):
2913
2669
return self.__class__ is other.__class__
2932
2688
"""Is this format supported?
2934
2690
Supported formats can be initialized and opened.
2935
Unsupported formats may not support initialization or committing or
2691
Unsupported formats may not support initialization or committing or
2936
2692
some other features depending on the reason for not being supported.
2940
def supports_content_filtering(self):
2941
"""True if this format supports content filtering."""
2944
def supports_views(self):
2945
"""True if this format supports stored views."""
2949
2697
def register_format(klass, format):
2950
2698
klass._formats[format.get_format_string()] = format
2953
def register_extra_format(klass, format):
2954
klass._extra_formats.append(format)
2957
def unregister_extra_format(klass, format):
2958
klass._extra_formats.remove(format)
2961
def get_formats(klass):
2962
return klass._formats.values() + klass._extra_formats
2965
2701
def set_default_format(klass, format):
2966
2702
klass._default_format = format
2969
2705
def unregister_format(klass, format):
2706
assert klass._formats[format.get_format_string()] is format
2970
2707
del klass._formats[format.get_format_string()]
2973
2710
class WorkingTreeFormat2(WorkingTreeFormat):
2974
"""The second working tree format.
2711
"""The second working tree format.
2976
2713
This format modified the hash cache from the format 1 hash cache.
2979
2716
upgrade_recommended = True
2981
requires_normalized_unicode_filenames = True
2983
case_sensitive_filename = "Branch-FoRMaT"
2985
missing_parent_conflicts = False
2987
2718
def get_format_description(self):
2988
2719
"""See WorkingTreeFormat.get_format_description()."""
2989
2720
return "Working tree format 2"
2991
def _stub_initialize_on_transport(self, transport, file_mode):
2992
"""Workaround: create control files for a remote working tree.
2722
def stub_initialize_remote(self, control_files):
2723
"""As a special workaround create critical control files for a remote working tree
2994
2725
This ensures that it can later be updated and dealt with locally,
2995
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2726
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2996
2727
no working tree. (See bug #43064).
2998
2729
sio = StringIO()
2999
inv = inventory.Inventory()
3000
2731
xml5.serializer_v5.write_inventory(inv, sio, working=True)
3002
transport.put_file('inventory', sio, file_mode)
3003
transport.put_bytes('pending-merges', '', file_mode)
3005
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3006
accelerator_tree=None, hardlink=False):
2733
control_files.put('inventory', sio)
2735
control_files.put_bytes('pending-merges', '')
2738
def initialize(self, a_bzrdir, revision_id=None, from_branch=None):
3007
2739
"""See WorkingTreeFormat.initialize()."""
3008
2740
if not isinstance(a_bzrdir.transport, LocalTransport):
3009
2741
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3097
2825
def _open_control_files(self, a_bzrdir):
3098
2826
transport = a_bzrdir.get_workingtree_transport(None)
3099
return LockableFiles(transport, self._lock_file_name,
2827
return LockableFiles(transport, self._lock_file_name,
3100
2828
self._lock_class)
3102
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3103
accelerator_tree=None, hardlink=False):
2830
def initialize(self, a_bzrdir, revision_id=None, from_branch=None):
3104
2831
"""See WorkingTreeFormat.initialize().
3106
:param revision_id: if supplied, create a working tree at a different
3107
revision than the branch is at.
3108
:param accelerator_tree: A tree which can be used for retrieving file
3109
contents more quickly than the revision tree, i.e. a workingtree.
3110
The revision tree will be used for cases where accelerator_tree's
3111
content is different.
3112
:param hardlink: If true, hard-link files from accelerator_tree,
2833
revision_id allows creating a working tree at a different
2834
revision than the branch is at.
3115
2836
if not isinstance(a_bzrdir.transport, LocalTransport):
3116
2837
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3193
2913
return self.get_format_string()
3196
__default_format = WorkingTreeFormat6()
2916
__default_format = WorkingTreeFormat4()
3197
2917
WorkingTreeFormat.register_format(__default_format)
3198
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3199
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3200
2918
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3201
2919
WorkingTreeFormat.set_default_format(__default_format)
3202
# Register extra formats which have no format string are not discoverable
3203
# and not independently creatable. They are implicitly created as part of
3204
# e.g. older Bazaar formats or foreign formats.
3205
WorkingTreeFormat.register_extra_format(WorkingTreeFormat2())
2920
# formats which have no format string are not discoverable
2921
# and not independently creatable, so are not registered.
2922
_legacy_formats = [WorkingTreeFormat2(),