1
# Copyright (C) 2005-2011 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
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
17
"""WorkingTree object and friends.
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
23
new revision based on the workingtree and its inventory.
25
At the moment every WorkingTree has its own branch. Remote
26
WorkingTrees aren't supported.
28
To get a WorkingTree, call bzrdir.open_workingtree() or
29
WorkingTree.open(dir).
33
from cStringIO import StringIO
37
from bzrlib.lazy_import import lazy_import
38
lazy_import(globals(), """
39
from bisect import bisect_left
50
conflicts as _mod_conflicts,
53
filters as _mod_filters,
61
revision as _mod_revision,
73
from bzrlib import symbol_versioning
74
from bzrlib.decorators import needs_read_lock, needs_write_lock
75
from bzrlib.lock import LogicalLockResult
76
import bzrlib.mutabletree
77
from bzrlib.mutabletree import needs_tree_write_lock
78
from bzrlib import osutils
79
from bzrlib.osutils import (
89
from bzrlib.trace import mutter, note
90
from bzrlib.revision import CURRENT_REVISION
91
from bzrlib.symbol_versioning import (
97
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
98
# TODO: Modifying the conflict objects or their type is currently nearly
99
# impossible as there is no clear relationship between the working tree format
100
# and the conflict list file format.
101
CONFLICT_HEADER_1 = "BZR conflict list format 1"
103
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
106
class TreeEntry(object):
107
"""An entry that implements the minimum interface used by commands.
109
This needs further inspection, it may be better to have
110
InventoryEntries without ids - though that seems wrong. For now,
111
this is a parallel hierarchy to InventoryEntry, and needs to become
112
one of several things: decorates to that hierarchy, children of, or
114
Another note is that these objects are currently only used when there is
115
no InventoryEntry available - i.e. for unversioned objects.
116
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
119
def __eq__(self, other):
120
# yes, this us ugly, TODO: best practice __eq__ style.
121
return (isinstance(other, TreeEntry)
122
and other.__class__ == self.__class__)
124
def kind_character(self):
128
class TreeDirectory(TreeEntry):
129
"""See TreeEntry. This is a directory in a working tree."""
131
def __eq__(self, other):
132
return (isinstance(other, TreeDirectory)
133
and other.__class__ == self.__class__)
135
def kind_character(self):
139
class TreeFile(TreeEntry):
140
"""See TreeEntry. This is a regular file in a working tree."""
142
def __eq__(self, other):
143
return (isinstance(other, TreeFile)
144
and other.__class__ == self.__class__)
146
def kind_character(self):
150
class TreeLink(TreeEntry):
151
"""See TreeEntry. This is a symlink in a working tree."""
153
def __eq__(self, other):
154
return (isinstance(other, TreeLink)
155
and other.__class__ == self.__class__)
157
def kind_character(self):
161
class WorkingTree(bzrlib.mutabletree.MutableTree,
162
controldir.ControlComponent):
163
"""Working copy tree.
165
:ivar basedir: The root of the tree on disk. This is a unicode path object
166
(as opposed to a URL).
169
# override this to set the strategy for storing views
170
def _make_views(self):
171
return views.DisabledViews(self)
173
def __init__(self, basedir='.',
174
branch=DEPRECATED_PARAMETER,
179
"""Construct a WorkingTree instance. This is not a public API.
181
:param branch: A branch to override probing for the branch.
183
self._format = _format
184
self.bzrdir = _bzrdir
186
raise errors.BzrError("Please use bzrdir.open_workingtree or "
187
"WorkingTree.open() to obtain a WorkingTree.")
188
basedir = safe_unicode(basedir)
189
mutter("opening working tree %r", basedir)
190
if deprecated_passed(branch):
191
self._branch = branch
193
self._branch = self.bzrdir.open_branch()
194
self.basedir = realpath(basedir)
195
self._control_files = _control_files
196
self._transport = self._control_files._transport
197
# update the whole cache up front and write to disk if anything changed;
198
# in the future we might want to do this more selectively
199
# two possible ways offer themselves : in self._unlock, write the cache
200
# if needed, or, when the cache sees a change, append it to the hash
201
# cache file, and have the parser take the most recent entry for a
203
wt_trans = self.bzrdir.get_workingtree_transport(None)
204
cache_filename = wt_trans.local_abspath('stat-cache')
205
self._hashcache = hashcache.HashCache(basedir, cache_filename,
206
self.bzrdir._get_file_mode(),
207
self._content_filter_stack_provider())
210
# is this scan needed ? it makes things kinda slow.
217
self._detect_case_handling()
218
self._rules_searcher = None
219
self.views = self._make_views()
222
def user_transport(self):
223
return self.bzrdir.user_transport
226
def control_transport(self):
227
return self._transport
229
def is_control_filename(self, filename):
230
"""True if filename is the name of a control file in this tree.
232
:param filename: A filename within the tree. This is a relative path
233
from the root of this tree.
235
This is true IF and ONLY IF the filename is part of the meta data
236
that bzr controls in this tree. I.E. a random .bzr directory placed
237
on disk will not be a control file for this tree.
239
return self.bzrdir.is_control_filename(filename)
241
def _detect_case_handling(self):
242
wt_trans = self.bzrdir.get_workingtree_transport(None)
244
wt_trans.stat(self._format.case_sensitive_filename)
245
except errors.NoSuchFile:
246
self.case_sensitive = True
248
self.case_sensitive = False
250
self._setup_directory_is_tree_reference()
253
fget=lambda self: self._branch,
254
doc="""The branch this WorkingTree is connected to.
256
This cannot be set - it is reflective of the actual disk structure
257
the working tree has been constructed from.
260
def break_lock(self):
261
"""Break a lock if one is present from another instance.
263
Uses the ui factory to ask for confirmation if the lock may be from
266
This will probe the repository for its lock as well.
268
self._control_files.break_lock()
269
self.branch.break_lock()
271
def requires_rich_root(self):
272
return self._format.requires_rich_root
274
def supports_tree_reference(self):
277
def supports_content_filtering(self):
278
return self._format.supports_content_filtering()
280
def supports_views(self):
281
return self.views.supports_views()
284
def open(path=None, _unsupported=False):
285
"""Open an existing working tree at path.
289
path = osutils.getcwd()
290
control = bzrdir.BzrDir.open(path, _unsupported)
291
return control.open_workingtree(_unsupported)
294
def open_containing(path=None):
295
"""Open an existing working tree which has its root about path.
297
This probes for a working tree at path and searches upwards from there.
299
Basically we keep looking up until we find the control directory or
300
run into /. If there isn't one, raises NotBranchError.
301
TODO: give this a new exception.
302
If there is one, it is returned, along with the unused portion of path.
304
:return: The WorkingTree that contains 'path', and the rest of path
307
path = osutils.getcwd()
308
control, relpath = bzrdir.BzrDir.open_containing(path)
309
return control.open_workingtree(), relpath
312
def open_containing_paths(file_list, default_directory=None,
313
canonicalize=True, apply_view=True):
314
"""Open the WorkingTree that contains a set of paths.
316
Fail if the paths given are not all in a single tree.
318
This is used for the many command-line interfaces that take a list of
319
any number of files and that require they all be in the same tree.
321
if default_directory is None:
322
default_directory = u'.'
323
# recommended replacement for builtins.internal_tree_files
324
if file_list is None or len(file_list) == 0:
325
tree = WorkingTree.open_containing(default_directory)[0]
326
# XXX: doesn't really belong here, and seems to have the strange
327
# side effect of making it return a bunch of files, not the whole
328
# tree -- mbp 20100716
329
if tree.supports_views() and apply_view:
330
view_files = tree.views.lookup_view()
332
file_list = view_files
333
view_str = views.view_display_str(view_files)
334
note("Ignoring files outside view. View is %s" % view_str)
335
return tree, file_list
336
if default_directory == u'.':
339
seed = default_directory
340
file_list = [osutils.pathjoin(default_directory, f)
342
tree = WorkingTree.open_containing(seed)[0]
343
return tree, tree.safe_relpath_files(file_list, canonicalize,
344
apply_view=apply_view)
346
def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
347
"""Convert file_list into a list of relpaths in tree.
349
:param self: A tree to operate on.
350
:param file_list: A list of user provided paths or None.
351
:param apply_view: if True and a view is set, apply it or check that
352
specified files are within it
353
:return: A list of relative paths.
354
:raises errors.PathNotChild: When a provided path is in a different self
357
if file_list is None:
359
if self.supports_views() and apply_view:
360
view_files = self.views.lookup_view()
364
# self.relpath exists as a "thunk" to osutils, but canonical_relpath
365
# doesn't - fix that up here before we enter the loop.
367
fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
370
for filename in file_list:
371
relpath = fixer(osutils.dereference_path(filename))
372
if view_files and not osutils.is_inside_any(view_files, relpath):
373
raise errors.FileOutsideView(filename, view_files)
374
new_list.append(relpath)
378
def open_downlevel(path=None):
379
"""Open an unsupported working tree.
381
Only intended for advanced situations like upgrading part of a bzrdir.
383
return WorkingTree.open(path, _unsupported=True)
386
def find_trees(location):
387
def list_current(transport):
388
return [d for d in transport.list_dir('') if d != '.bzr']
389
def evaluate(bzrdir):
391
tree = bzrdir.open_workingtree()
392
except errors.NoWorkingTree:
396
t = transport.get_transport(location)
397
iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
398
list_current=list_current)
399
return [tr for tr in iterator if tr is not None]
401
def all_file_ids(self):
402
"""See Tree.iter_all_file_ids"""
403
raise NotImplementedError(self.all_file_ids)
406
return "<%s of %s>" % (self.__class__.__name__,
407
getattr(self, 'basedir', None))
409
def abspath(self, filename):
410
return pathjoin(self.basedir, filename)
412
def basis_tree(self):
413
"""Return RevisionTree for the current last revision.
415
If the left most parent is a ghost then the returned tree will be an
416
empty tree - one obtained by calling
417
repository.revision_tree(NULL_REVISION).
420
revision_id = self.get_parent_ids()[0]
422
# no parents, return an empty revision tree.
423
# in the future this should return the tree for
424
# 'empty:' - the implicit root empty tree.
425
return self.branch.repository.revision_tree(
426
_mod_revision.NULL_REVISION)
428
return self.revision_tree(revision_id)
429
except errors.NoSuchRevision:
431
# No cached copy available, retrieve from the repository.
432
# FIXME? RBC 20060403 should we cache the inventory locally
435
return self.branch.repository.revision_tree(revision_id)
436
except (errors.RevisionNotPresent, errors.NoSuchRevision):
437
# the basis tree *may* be a ghost or a low level error may have
438
# occurred. If the revision is present, its a problem, if its not
440
if self.branch.repository.has_revision(revision_id):
442
# the basis tree is a ghost so return an empty tree.
443
return self.branch.repository.revision_tree(
444
_mod_revision.NULL_REVISION)
447
self._flush_ignore_list_cache()
449
def relpath(self, path):
450
"""Return the local path portion from a given path.
452
The path may be absolute or relative. If its a relative path it is
453
interpreted relative to the python current working directory.
455
return osutils.relpath(self.basedir, path)
457
def has_filename(self, filename):
458
return osutils.lexists(self.abspath(filename))
460
def get_file(self, file_id, path=None, filtered=True):
461
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
463
def get_file_with_stat(self, file_id, path=None, filtered=True,
464
_fstat=osutils.fstat):
465
"""See Tree.get_file_with_stat."""
467
path = self.id2path(file_id)
468
file_obj = self.get_file_byname(path, filtered=False)
469
stat_value = _fstat(file_obj.fileno())
470
if filtered and self.supports_content_filtering():
471
filters = self._content_filter_stack(path)
472
file_obj = _mod_filters.filtered_input_file(file_obj, filters)
473
return (file_obj, stat_value)
475
def get_file_text(self, file_id, path=None, filtered=True):
476
my_file = self.get_file(file_id, path=path, filtered=filtered)
478
return my_file.read()
482
def get_file_byname(self, filename, filtered=True):
483
path = self.abspath(filename)
485
if filtered and self.supports_content_filtering():
486
filters = self._content_filter_stack(filename)
487
return _mod_filters.filtered_input_file(f, filters)
491
def get_file_lines(self, file_id, path=None, filtered=True):
492
"""See Tree.get_file_lines()"""
493
file = self.get_file(file_id, path, filtered=filtered)
495
return file.readlines()
499
def _get_ancestors(self, default_revision):
500
ancestors = set([default_revision])
501
for parent_id in self.get_parent_ids():
502
ancestors.update(self.branch.repository.get_ancestry(
503
parent_id, topo_sorted=False))
506
def get_parent_ids(self):
507
"""See Tree.get_parent_ids.
509
This implementation reads the pending merges list and last_revision
510
value and uses that to decide what the parents list should be.
512
last_rev = _mod_revision.ensure_null(self._last_revision())
513
if _mod_revision.NULL_REVISION == last_rev:
518
merges_bytes = self._transport.get_bytes('pending-merges')
519
except errors.NoSuchFile:
522
for l in osutils.split_lines(merges_bytes):
523
revision_id = l.rstrip('\n')
524
parents.append(revision_id)
527
def get_root_id(self):
528
"""Return the id of this trees root"""
529
raise NotImplementedError(self.get_root_id)
532
def clone(self, to_bzrdir, revision_id=None):
533
"""Duplicate this working tree into to_bzr, including all state.
535
Specifically modified files are kept as modified, but
536
ignored and unknown files are discarded.
538
If you want to make a new line of development, see bzrdir.sprout()
541
If not None, the cloned tree will have its last revision set to
542
revision, and difference between the source trees last revision
543
and this one merged in.
545
# assumes the target bzr dir format is compatible.
546
result = to_bzrdir.create_workingtree()
547
self.copy_content_into(result, revision_id)
551
def copy_content_into(self, tree, revision_id=None):
552
"""Copy the current content and user files of this tree into tree."""
553
tree.set_root_id(self.get_root_id())
554
if revision_id is None:
555
merge.transform_tree(tree, self)
557
# TODO now merge from tree.last_revision to revision (to preserve
558
# user local changes)
559
merge.transform_tree(tree, self)
560
tree.set_parent_ids([revision_id])
562
def id2abspath(self, file_id):
563
return self.abspath(self.id2path(file_id))
565
def _check_for_tree_references(self, iterator):
566
"""See if directories have become tree-references."""
567
blocked_parent_ids = set()
568
for path, ie in iterator:
569
if ie.parent_id in blocked_parent_ids:
570
# This entry was pruned because one of its parents became a
571
# TreeReference. If this is a directory, mark it as blocked.
572
if ie.kind == 'directory':
573
blocked_parent_ids.add(ie.file_id)
575
if ie.kind == 'directory' and self._directory_is_tree_reference(path):
576
# This InventoryDirectory needs to be a TreeReference
577
ie = inventory.TreeReference(ie.file_id, ie.name, ie.parent_id)
578
blocked_parent_ids.add(ie.file_id)
581
def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
582
"""See Tree.iter_entries_by_dir()"""
583
# The only trick here is that if we supports_tree_reference then we
584
# need to detect if a directory becomes a tree-reference.
585
iterator = super(WorkingTree, self).iter_entries_by_dir(
586
specific_file_ids=specific_file_ids,
587
yield_parents=yield_parents)
588
if not self.supports_tree_reference():
591
return self._check_for_tree_references(iterator)
593
def get_file_size(self, file_id):
594
"""See Tree.get_file_size"""
595
# XXX: this returns the on-disk size; it should probably return the
598
return os.path.getsize(self.id2abspath(file_id))
600
if e.errno != errno.ENOENT:
605
def get_file_sha1(self, file_id, path=None, stat_value=None):
606
# FIXME: Shouldn't this be in Tree?
607
raise NotImplementedError(self.get_file_sha1)
609
@needs_tree_write_lock
610
def _gather_kinds(self, files, kinds):
611
"""See MutableTree._gather_kinds."""
612
for pos, f in enumerate(files):
613
if kinds[pos] is None:
614
fullpath = normpath(self.abspath(f))
616
kinds[pos] = file_kind(fullpath)
618
if e.errno == errno.ENOENT:
619
raise errors.NoSuchFile(fullpath)
622
def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
623
"""Add revision_id as a parent.
625
This is equivalent to retrieving the current list of parent ids
626
and setting the list to its value plus revision_id.
628
:param revision_id: The revision id to add to the parent list. It may
629
be a ghost revision as long as its not the first parent to be
630
added, or the allow_leftmost_as_ghost parameter is set True.
631
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
633
parents = self.get_parent_ids() + [revision_id]
634
self.set_parent_ids(parents, allow_leftmost_as_ghost=len(parents) > 1
635
or allow_leftmost_as_ghost)
637
@needs_tree_write_lock
638
def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
639
"""Add revision_id, tree tuple as a parent.
641
This is equivalent to retrieving the current list of parent trees
642
and setting the list to its value plus parent_tuple. See also
643
add_parent_tree_id - if you only have a parent id available it will be
644
simpler to use that api. If you have the parent already available, using
645
this api is preferred.
647
:param parent_tuple: The (revision id, tree) to add to the parent list.
648
If the revision_id is a ghost, pass None for the tree.
649
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
651
parent_ids = self.get_parent_ids() + [parent_tuple[0]]
652
if len(parent_ids) > 1:
653
# the leftmost may have already been a ghost, preserve that if it
655
allow_leftmost_as_ghost = True
656
self.set_parent_ids(parent_ids,
657
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
659
@needs_tree_write_lock
660
def add_pending_merge(self, *revision_ids):
661
# TODO: Perhaps should check at this point that the
662
# history of the revision is actually present?
663
parents = self.get_parent_ids()
665
for rev_id in revision_ids:
666
if rev_id in parents:
668
parents.append(rev_id)
671
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
673
def path_content_summary(self, path, _lstat=os.lstat,
674
_mapper=osutils.file_kind_from_stat_mode):
675
"""See Tree.path_content_summary."""
676
abspath = self.abspath(path)
678
stat_result = _lstat(abspath)
680
if getattr(e, 'errno', None) == errno.ENOENT:
682
return ('missing', None, None, None)
683
# propagate other errors
685
kind = _mapper(stat_result.st_mode)
687
return self._file_content_summary(path, stat_result)
688
elif kind == 'directory':
689
# perhaps it looks like a plain directory, but it's really a
691
if self._directory_is_tree_reference(path):
692
kind = 'tree-reference'
693
return kind, None, None, None
694
elif kind == 'symlink':
695
target = osutils.readlink(abspath)
696
return ('symlink', None, None, target)
698
return (kind, None, None, None)
700
def _file_content_summary(self, path, stat_result):
701
size = stat_result.st_size
702
executable = self._is_executable_from_path_and_stat(path, stat_result)
703
# try for a stat cache lookup
704
return ('file', size, executable, self._sha_from_stat(
707
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
708
"""Common ghost checking functionality from set_parent_*.
710
This checks that the left hand-parent exists if there are any
713
if len(revision_ids) > 0:
714
leftmost_id = revision_ids[0]
715
if (not allow_leftmost_as_ghost and not
716
self.branch.repository.has_revision(leftmost_id)):
717
raise errors.GhostRevisionUnusableHere(leftmost_id)
719
def _set_merges_from_parent_ids(self, parent_ids):
720
merges = parent_ids[1:]
721
self._transport.put_bytes('pending-merges', '\n'.join(merges),
722
mode=self.bzrdir._get_file_mode())
724
def _filter_parent_ids_by_ancestry(self, revision_ids):
725
"""Check that all merged revisions are proper 'heads'.
727
This will always return the first revision_id, and any merged revisions
730
if len(revision_ids) == 0:
732
graph = self.branch.repository.get_graph()
733
heads = graph.heads(revision_ids)
734
new_revision_ids = revision_ids[:1]
735
for revision_id in revision_ids[1:]:
736
if revision_id in heads and revision_id not in new_revision_ids:
737
new_revision_ids.append(revision_id)
738
if new_revision_ids != revision_ids:
739
mutter('requested to set revision_ids = %s,'
740
' but filtered to %s', revision_ids, new_revision_ids)
741
return new_revision_ids
743
@needs_tree_write_lock
744
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
745
"""Set the parent ids to revision_ids.
747
See also set_parent_trees. This api will try to retrieve the tree data
748
for each element of revision_ids from the trees repository. If you have
749
tree data already available, it is more efficient to use
750
set_parent_trees rather than set_parent_ids. set_parent_ids is however
751
an easier API to use.
753
:param revision_ids: The revision_ids to set as the parent ids of this
754
working tree. Any of these may be ghosts.
756
self._check_parents_for_ghosts(revision_ids,
757
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
758
for revision_id in revision_ids:
759
_mod_revision.check_not_reserved_id(revision_id)
761
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
763
if len(revision_ids) > 0:
764
self.set_last_revision(revision_ids[0])
766
self.set_last_revision(_mod_revision.NULL_REVISION)
768
self._set_merges_from_parent_ids(revision_ids)
770
@needs_tree_write_lock
771
def set_pending_merges(self, rev_list):
772
parents = self.get_parent_ids()
773
leftmost = parents[:1]
774
new_parents = leftmost + rev_list
775
self.set_parent_ids(new_parents)
777
@needs_tree_write_lock
778
def set_merge_modified(self, modified_hashes):
780
for file_id, hash in modified_hashes.iteritems():
781
yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
783
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
785
def _sha_from_stat(self, path, stat_result):
786
"""Get a sha digest from the tree's stat cache.
788
The default implementation assumes no stat cache is present.
790
:param path: The path.
791
:param stat_result: The stat result being looked up.
795
def _put_rio(self, filename, stanzas, header):
796
self._must_be_locked()
797
my_file = _mod_rio.rio_file(stanzas, header)
798
self._transport.put_file(filename, my_file,
799
mode=self.bzrdir._get_file_mode())
801
@needs_write_lock # because merge pulls data into the branch.
802
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
803
merge_type=None, force=False):
804
"""Merge from a branch into this working tree.
806
:param branch: The branch to merge from.
807
:param to_revision: If non-None, the merge will merge to to_revision,
808
but not beyond it. to_revision does not need to be in the history
809
of the branch when it is supplied. If None, to_revision defaults to
810
branch.last_revision().
812
from bzrlib.merge import Merger, Merge3Merger
813
merger = Merger(self.branch, this_tree=self)
814
# check that there are no local alterations
815
if not force and self.has_changes():
816
raise errors.UncommittedChanges(self)
817
if to_revision is None:
818
to_revision = _mod_revision.ensure_null(branch.last_revision())
819
merger.other_rev_id = to_revision
820
if _mod_revision.is_null(merger.other_rev_id):
821
raise errors.NoCommits(branch)
822
self.branch.fetch(branch, last_revision=merger.other_rev_id)
823
merger.other_basis = merger.other_rev_id
824
merger.other_tree = self.branch.repository.revision_tree(
826
merger.other_branch = branch
827
if from_revision is None:
830
merger.set_base_revision(from_revision, branch)
831
if merger.base_rev_id == merger.other_rev_id:
832
raise errors.PointlessMerge
833
merger.backup_files = False
834
if merge_type is None:
835
merger.merge_type = Merge3Merger
837
merger.merge_type = merge_type
838
merger.set_interesting_files(None)
839
merger.show_base = False
840
merger.reprocess = False
841
conflicts = merger.do_merge()
845
def merge_modified(self):
846
"""Return a dictionary of files modified by a merge.
848
The list is initialized by WorkingTree.set_merge_modified, which is
849
typically called after we make some automatic updates to the tree
852
This returns a map of file_id->sha1, containing only files which are
853
still in the working inventory and have that text hash.
855
raise NotImplementedError(self.merge_modified)
858
def mkdir(self, path, file_id=None):
859
"""See MutableTree.mkdir()."""
861
file_id = generate_ids.gen_file_id(os.path.basename(path))
862
os.mkdir(self.abspath(path))
863
self.add(path, file_id, 'directory')
866
def get_symlink_target(self, file_id, path=None):
868
abspath = self.abspath(path)
870
abspath = self.id2abspath(file_id)
871
target = osutils.readlink(abspath)
874
def subsume(self, other_tree):
875
raise NotImplementedError(self.subsume)
877
def _setup_directory_is_tree_reference(self):
878
if self._branch.repository._format.supports_tree_reference:
879
self._directory_is_tree_reference = \
880
self._directory_may_be_tree_reference
882
self._directory_is_tree_reference = \
883
self._directory_is_never_tree_reference
885
def _directory_is_never_tree_reference(self, relpath):
888
def _directory_may_be_tree_reference(self, relpath):
889
# as a special case, if a directory contains control files then
890
# it's a tree reference, except that the root of the tree is not
891
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
892
# TODO: We could ask all the control formats whether they
893
# recognize this directory, but at the moment there's no cheap api
894
# to do that. Since we probably can only nest bzr checkouts and
895
# they always use this name it's ok for now. -- mbp 20060306
897
# FIXME: There is an unhandled case here of a subdirectory
898
# containing .bzr but not a branch; that will probably blow up
899
# when you try to commit it. It might happen if there is a
900
# checkout in a subdirectory. This can be avoided by not adding
903
def extract(self, file_id, format=None):
904
"""Extract a subtree from this tree.
906
A new branch will be created, relative to the path for this tree.
908
raise NotImplementedError(self.extract)
911
"""Write the in memory meta data to disk."""
912
raise NotImplementedError(self.flush)
914
def _kind(self, relpath):
915
return osutils.file_kind(self.abspath(relpath))
917
def list_files(self, include_root=False, from_dir=None, recursive=True):
918
"""List all files as (path, class, kind, id, entry).
920
Lists, but does not descend into unversioned directories.
921
This does not include files that have been deleted in this
922
tree. Skips the control directory.
924
:param include_root: if True, return an entry for the root
925
:param from_dir: start from this directory or None for the root
926
:param recursive: whether to recurse into subdirectories or not
928
raise NotImplementedError(self.list_files)
930
def move(self, from_paths, to_dir=None, after=False):
933
to_dir must be known to the working tree.
935
If to_dir exists and is a directory, the files are moved into
936
it, keeping their old names.
938
Note that to_dir is only the last component of the new name;
939
this doesn't change the directory.
941
For each entry in from_paths the move mode will be determined
944
The first mode moves the file in the filesystem and updates the
945
working tree metadata. The second mode only updates the working tree
946
metadata without touching the file on the filesystem.
948
move uses the second mode if 'after == True' and the target is not
949
versioned but present in the working tree.
951
move uses the second mode if 'after == False' and the source is
952
versioned but no longer in the working tree, and the target is not
953
versioned but present in the working tree.
955
move uses the first mode if 'after == False' and the source is
956
versioned and present in the working tree, and the target is not
957
versioned and not present in the working tree.
959
Everything else results in an error.
961
This returns a list of (from_path, to_path) pairs for each
964
raise NotImplementedError(self.move)
966
@needs_tree_write_lock
967
def rename_one(self, from_rel, to_rel, after=False):
970
This can change the directory or the filename or both.
972
rename_one has several 'modes' to work. First, it can rename a physical
973
file and change the file_id. That is the normal mode. Second, it can
974
only change the file_id without touching any physical file.
976
rename_one uses the second mode if 'after == True' and 'to_rel' is not
977
versioned but present in the working tree.
979
rename_one uses the second mode if 'after == False' and 'from_rel' is
980
versioned but no longer in the working tree, and 'to_rel' is not
981
versioned but present in the working tree.
983
rename_one uses the first mode if 'after == False' and 'from_rel' is
984
versioned and present in the working tree, and 'to_rel' is not
985
versioned and not present in the working tree.
987
Everything else results in an error.
989
raise NotImplementedError(self.rename_one)
993
"""Return all unknown files.
995
These are files in the working directory that are not versioned or
996
control files or ignored.
998
# force the extras method to be fully executed before returning, to
999
# prevent race conditions with the lock
1001
[subp for subp in self.extras() if not self.is_ignored(subp)])
1003
def unversion(self, file_ids):
1004
"""Remove the file ids in file_ids from the current versioned set.
1006
When a file_id is unversioned, all of its children are automatically
1009
:param file_ids: The file ids to stop versioning.
1010
:raises: NoSuchId if any fileid is not currently versioned.
1012
raise NotImplementedError(self.unversion)
1015
def pull(self, source, overwrite=False, stop_revision=None,
1016
change_reporter=None, possible_transports=None, local=False,
1020
old_revision_info = self.branch.last_revision_info()
1021
basis_tree = self.basis_tree()
1022
count = self.branch.pull(source, overwrite, stop_revision,
1023
possible_transports=possible_transports,
1025
new_revision_info = self.branch.last_revision_info()
1026
if new_revision_info != old_revision_info:
1027
repository = self.branch.repository
1028
if repository._format.fast_deltas:
1029
parent_ids = self.get_parent_ids()
1031
basis_id = parent_ids[0]
1032
basis_tree = repository.revision_tree(basis_id)
1033
basis_tree.lock_read()
1035
new_basis_tree = self.branch.basis_tree()
1042
change_reporter=change_reporter,
1043
show_base=show_base)
1044
basis_root_id = basis_tree.get_root_id()
1045
new_root_id = new_basis_tree.get_root_id()
1046
if basis_root_id != new_root_id:
1047
self.set_root_id(new_root_id)
1050
# TODO - dedup parents list with things merged by pull ?
1051
# reuse the revisiontree we merged against to set the new
1053
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1054
# we have to pull the merge trees out again, because
1055
# merge_inner has set the ids. - this corner is not yet
1056
# layered well enough to prevent double handling.
1057
# XXX TODO: Fix the double handling: telling the tree about
1058
# the already known parent data is wasteful.
1059
merges = self.get_parent_ids()[1:]
1060
parent_trees.extend([
1061
(parent, repository.revision_tree(parent)) for
1063
self.set_parent_trees(parent_trees)
1069
def put_file_bytes_non_atomic(self, file_id, bytes):
1070
"""See MutableTree.put_file_bytes_non_atomic."""
1071
stream = file(self.id2abspath(file_id), 'wb')
1076
# TODO: update the hashcache here ?
1079
"""Yield all unversioned files in this WorkingTree.
1081
If there are any unversioned directories then only the directory is
1082
returned, not all its children. But if there are unversioned files
1083
under a versioned subdirectory, they are returned.
1085
Currently returned depth-first, sorted by name within directories.
1086
This is the same order used by 'osutils.walkdirs'.
1088
raise NotImplementedError(self.extras)
1090
def ignored_files(self):
1091
"""Yield list of PATH, IGNORE_PATTERN"""
1092
for subp in self.extras():
1093
pat = self.is_ignored(subp)
1097
def get_ignore_list(self):
1098
"""Return list of ignore patterns.
1100
Cached in the Tree object after the first call.
1102
ignoreset = getattr(self, '_ignoreset', None)
1103
if ignoreset is not None:
1106
ignore_globs = set()
1107
ignore_globs.update(ignores.get_runtime_ignores())
1108
ignore_globs.update(ignores.get_user_ignores())
1109
if self.has_filename(bzrlib.IGNORE_FILENAME):
1110
f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
1112
ignore_globs.update(ignores.parse_ignore_file(f))
1115
self._ignoreset = ignore_globs
1118
def _flush_ignore_list_cache(self):
1119
"""Resets the cached ignore list to force a cache rebuild."""
1120
self._ignoreset = None
1121
self._ignoreglobster = None
1123
def is_ignored(self, filename):
1124
r"""Check whether the filename matches an ignore pattern.
1126
Patterns containing '/' or '\' need to match the whole path;
1127
others match against only the last component. Patterns starting
1128
with '!' are ignore exceptions. Exceptions take precedence
1129
over regular patterns and cause the filename to not be ignored.
1131
If the file is ignored, returns the pattern which caused it to
1132
be ignored, otherwise None. So this can simply be used as a
1133
boolean if desired."""
1134
if getattr(self, '_ignoreglobster', None) is None:
1135
self._ignoreglobster = globbing.ExceptionGlobster(self.get_ignore_list())
1136
return self._ignoreglobster.match(filename)
1138
def kind(self, file_id):
1139
return file_kind(self.id2abspath(file_id))
1141
def stored_kind(self, file_id):
1142
"""See Tree.stored_kind"""
1143
raise NotImplementedError(self.stored_kind)
1145
def _comparison_data(self, entry, path):
1146
abspath = self.abspath(path)
1148
stat_value = os.lstat(abspath)
1150
if getattr(e, 'errno', None) == errno.ENOENT:
1157
mode = stat_value.st_mode
1158
kind = osutils.file_kind_from_stat_mode(mode)
1159
if not supports_executable():
1160
executable = entry is not None and entry.executable
1162
executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1163
return kind, executable, stat_value
1165
def _file_size(self, entry, stat_value):
1166
return stat_value.st_size
1168
def last_revision(self):
1169
"""Return the last revision of the branch for this tree.
1171
This format tree does not support a separate marker for last-revision
1172
compared to the branch.
1174
See MutableTree.last_revision
1176
return self._last_revision()
1179
def _last_revision(self):
1180
"""helper for get_parent_ids."""
1181
return _mod_revision.ensure_null(self.branch.last_revision())
1183
def is_locked(self):
1184
return self._control_files.is_locked()
1186
def _must_be_locked(self):
1187
if not self.is_locked():
1188
raise errors.ObjectNotLocked(self)
1190
def lock_read(self):
1191
"""Lock the tree for reading.
1193
This also locks the branch, and can be unlocked via self.unlock().
1195
:return: A bzrlib.lock.LogicalLockResult.
1197
if not self.is_locked():
1199
self.branch.lock_read()
1201
self._control_files.lock_read()
1202
return LogicalLockResult(self.unlock)
1204
self.branch.unlock()
1207
def lock_tree_write(self):
1208
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1210
:return: A bzrlib.lock.LogicalLockResult.
1212
if not self.is_locked():
1214
self.branch.lock_read()
1216
self._control_files.lock_write()
1217
return LogicalLockResult(self.unlock)
1219
self.branch.unlock()
1222
def lock_write(self):
1223
"""See MutableTree.lock_write, and WorkingTree.unlock.
1225
:return: A bzrlib.lock.LogicalLockResult.
1227
if not self.is_locked():
1229
self.branch.lock_write()
1231
self._control_files.lock_write()
1232
return LogicalLockResult(self.unlock)
1234
self.branch.unlock()
1237
def get_physical_lock_status(self):
1238
return self._control_files.get_physical_lock_status()
1240
def _reset_data(self):
1241
"""Reset transient data that cannot be revalidated."""
1242
raise NotImplementedError(self._reset_data)
1244
def set_last_revision(self, new_revision):
1245
"""Change the last revision in the working tree."""
1246
raise NotImplementedError(self.set_last_revision)
1248
def _change_last_revision(self, new_revision):
1249
"""Template method part of set_last_revision to perform the change.
1251
This is used to allow WorkingTree3 instances to not affect branch
1252
when their last revision is set.
1254
if _mod_revision.is_null(new_revision):
1255
self.branch.set_last_revision_info(0, new_revision)
1257
_mod_revision.check_not_reserved_id(new_revision)
1259
self.branch.generate_revision_history(new_revision)
1260
except errors.NoSuchRevision:
1261
# not present in the repo - dont try to set it deeper than the tip
1262
self.branch._set_revision_history([new_revision])
1265
@needs_tree_write_lock
1266
def remove(self, files, verbose=False, to_file=None, keep_files=True,
1268
"""Remove nominated files from the working tree metadata.
1270
:files: File paths relative to the basedir.
1271
:keep_files: If true, the files will also be kept.
1272
:force: Delete files and directories, even if they are changed and
1273
even if the directories are not empty.
1275
if isinstance(files, basestring):
1280
all_files = set() # specified and nested files
1281
unknown_nested_files=set()
1283
to_file = sys.stdout
1285
files_to_backup = []
1287
def recurse_directory_to_add_files(directory):
1288
# Recurse directory and add all files
1289
# so we can check if they have changed.
1290
for parent_info, file_infos in self.walkdirs(directory):
1291
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1292
# Is it versioned or ignored?
1293
if self.path2id(relpath):
1294
# Add nested content for deletion.
1295
all_files.add(relpath)
1297
# Files which are not versioned
1298
# should be treated as unknown.
1299
files_to_backup.append(relpath)
1301
for filename in files:
1302
# Get file name into canonical form.
1303
abspath = self.abspath(filename)
1304
filename = self.relpath(abspath)
1305
if len(filename) > 0:
1306
all_files.add(filename)
1307
recurse_directory_to_add_files(filename)
1309
files = list(all_files)
1312
return # nothing to do
1314
# Sort needed to first handle directory content before the directory
1315
files.sort(reverse=True)
1317
# Bail out if we are going to delete files we shouldn't
1318
if not keep_files and not force:
1319
for (file_id, path, content_change, versioned, parent_id, name,
1320
kind, executable) in self.iter_changes(self.basis_tree(),
1321
include_unchanged=True, require_versioned=False,
1322
want_unversioned=True, specific_files=files):
1323
if versioned[0] == False:
1324
# The record is unknown or newly added
1325
files_to_backup.append(path[1])
1326
elif (content_change and (kind[1] is not None) and
1327
osutils.is_inside_any(files, path[1])):
1328
# Versioned and changed, but not deleted, and still
1329
# in one of the dirs to be deleted.
1330
files_to_backup.append(path[1])
1332
def backup(file_to_backup):
1333
backup_name = self.bzrdir._available_backup_name(file_to_backup)
1334
osutils.rename(abs_path, self.abspath(backup_name))
1335
return "removed %s (but kept a copy: %s)" % (file_to_backup,
1338
# Build inv_delta and delete files where applicable,
1339
# do this before any modifications to meta data.
1341
fid = self.path2id(f)
1344
message = "%s is not versioned." % (f,)
1347
# having removed it, it must be either ignored or unknown
1348
if self.is_ignored(f):
1352
# XXX: Really should be a more abstract reporter interface
1353
kind_ch = osutils.kind_marker(self.kind(fid))
1354
to_file.write(new_status + ' ' + f + kind_ch + '\n')
1356
inv_delta.append((f, None, fid, None))
1357
message = "removed %s" % (f,)
1360
abs_path = self.abspath(f)
1361
if osutils.lexists(abs_path):
1362
if (osutils.isdir(abs_path) and
1363
len(os.listdir(abs_path)) > 0):
1365
osutils.rmtree(abs_path)
1366
message = "deleted %s" % (f,)
1370
if f in files_to_backup:
1373
osutils.delete_any(abs_path)
1374
message = "deleted %s" % (f,)
1375
elif message is not None:
1376
# Only care if we haven't done anything yet.
1377
message = "%s does not exist." % (f,)
1379
# Print only one message (if any) per file.
1380
if message is not None:
1382
self.apply_inventory_delta(inv_delta)
1384
@needs_tree_write_lock
1385
def revert(self, filenames=None, old_tree=None, backups=True,
1386
pb=None, report_changes=False):
1387
from bzrlib.conflicts import resolve
1390
symbol_versioning.warn('Using [] to revert all files is deprecated'
1391
' as of bzr 0.91. Please use None (the default) instead.',
1392
DeprecationWarning, stacklevel=2)
1393
if old_tree is None:
1394
basis_tree = self.basis_tree()
1395
basis_tree.lock_read()
1396
old_tree = basis_tree
1400
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1402
if filenames is None and len(self.get_parent_ids()) > 1:
1404
last_revision = self.last_revision()
1405
if last_revision != _mod_revision.NULL_REVISION:
1406
if basis_tree is None:
1407
basis_tree = self.basis_tree()
1408
basis_tree.lock_read()
1409
parent_trees.append((last_revision, basis_tree))
1410
self.set_parent_trees(parent_trees)
1413
resolve(self, filenames, ignore_misses=True, recursive=True)
1415
if basis_tree is not None:
1419
def revision_tree(self, revision_id):
1420
"""See Tree.revision_tree.
1422
WorkingTree can supply revision_trees for the basis revision only
1423
because there is only one cached inventory in the bzr directory.
1425
raise NotImplementedError(self.revision_tree)
1427
@needs_tree_write_lock
1428
def set_root_id(self, file_id):
1429
"""Set the root id for this tree."""
1433
'WorkingTree.set_root_id with fileid=None')
1434
file_id = osutils.safe_file_id(file_id)
1435
self._set_root_id(file_id)
1437
def _set_root_id(self, file_id):
1438
"""Set the root id for this tree, in a format specific manner.
1440
:param file_id: The file id to assign to the root. It must not be
1441
present in the current inventory or an error will occur. It must
1442
not be None, but rather a valid file id.
1444
raise NotImplementedError(self._set_root_id)
1447
"""See Branch.unlock.
1449
WorkingTree locking just uses the Branch locking facilities.
1450
This is current because all working trees have an embedded branch
1451
within them. IF in the future, we were to make branch data shareable
1452
between multiple working trees, i.e. via shared storage, then we
1453
would probably want to lock both the local tree, and the branch.
1455
raise NotImplementedError(self.unlock)
1459
def update(self, change_reporter=None, possible_transports=None,
1460
revision=None, old_tip=_marker, show_base=False):
1461
"""Update a working tree along its branch.
1463
This will update the branch if its bound too, which means we have
1464
multiple trees involved:
1466
- The new basis tree of the master.
1467
- The old basis tree of the branch.
1468
- The old basis tree of the working tree.
1469
- The current working tree state.
1471
Pathologically, all three may be different, and non-ancestors of each
1472
other. Conceptually we want to:
1474
- Preserve the wt.basis->wt.state changes
1475
- Transform the wt.basis to the new master basis.
1476
- Apply a merge of the old branch basis to get any 'local' changes from
1478
- Restore the wt.basis->wt.state changes.
1480
There isn't a single operation at the moment to do that, so we:
1482
- Merge current state -> basis tree of the master w.r.t. the old tree
1484
- Do a 'normal' merge of the old branch basis if it is relevant.
1486
:param revision: The target revision to update to. Must be in the
1488
:param old_tip: If branch.update() has already been run, the value it
1489
returned (old tip of the branch or None). _marker is used
1492
if self.branch.get_bound_location() is not None:
1494
update_branch = (old_tip is self._marker)
1496
self.lock_tree_write()
1497
update_branch = False
1500
old_tip = self.branch.update(possible_transports)
1502
if old_tip is self._marker:
1504
return self._update_tree(old_tip, change_reporter, revision, show_base)
1508
@needs_tree_write_lock
1509
def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
1511
"""Update a tree to the master branch.
1513
:param old_tip: if supplied, the previous tip revision the branch,
1514
before it was changed to the master branch's tip.
1516
# here if old_tip is not None, it is the old tip of the branch before
1517
# it was updated from the master branch. This should become a pending
1518
# merge in the working tree to preserve the user existing work. we
1519
# cant set that until we update the working trees last revision to be
1520
# one from the new branch, because it will just get absorbed by the
1521
# parent de-duplication logic.
1523
# We MUST save it even if an error occurs, because otherwise the users
1524
# local work is unreferenced and will appear to have been lost.
1528
last_rev = self.get_parent_ids()[0]
1530
last_rev = _mod_revision.NULL_REVISION
1531
if revision is None:
1532
revision = self.branch.last_revision()
1534
old_tip = old_tip or _mod_revision.NULL_REVISION
1536
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
1537
# the branch we are bound to was updated
1538
# merge those changes in first
1539
base_tree = self.basis_tree()
1540
other_tree = self.branch.repository.revision_tree(old_tip)
1541
nb_conflicts = merge.merge_inner(self.branch, other_tree,
1542
base_tree, this_tree=self,
1543
change_reporter=change_reporter,
1544
show_base=show_base)
1546
self.add_parent_tree((old_tip, other_tree))
1547
note('Rerun update after fixing the conflicts.')
1550
if last_rev != _mod_revision.ensure_null(revision):
1551
# the working tree is up to date with the branch
1552
# we can merge the specified revision from master
1553
to_tree = self.branch.repository.revision_tree(revision)
1554
to_root_id = to_tree.get_root_id()
1556
basis = self.basis_tree()
1559
if (basis.get_root_id() is None or basis.get_root_id() != to_root_id):
1560
self.set_root_id(to_root_id)
1565
# determine the branch point
1566
graph = self.branch.repository.get_graph()
1567
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
1569
base_tree = self.branch.repository.revision_tree(base_rev_id)
1571
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
1573
change_reporter=change_reporter,
1574
show_base=show_base)
1575
self.set_last_revision(revision)
1576
# TODO - dedup parents list with things merged by pull ?
1577
# reuse the tree we've updated to to set the basis:
1578
parent_trees = [(revision, to_tree)]
1579
merges = self.get_parent_ids()[1:]
1580
# Ideally we ask the tree for the trees here, that way the working
1581
# tree can decide whether to give us the entire tree or give us a
1582
# lazy initialised tree. dirstate for instance will have the trees
1583
# in ram already, whereas a last-revision + basis-inventory tree
1584
# will not, but also does not need them when setting parents.
1585
for parent in merges:
1586
parent_trees.append(
1587
(parent, self.branch.repository.revision_tree(parent)))
1588
if not _mod_revision.is_null(old_tip):
1589
parent_trees.append(
1590
(old_tip, self.branch.repository.revision_tree(old_tip)))
1591
self.set_parent_trees(parent_trees)
1592
last_rev = parent_trees[0][0]
1595
def _write_hashcache_if_dirty(self):
1596
"""Write out the hashcache if it is dirty."""
1597
if self._hashcache.needs_write:
1599
self._hashcache.write()
1601
if e.errno not in (errno.EPERM, errno.EACCES):
1603
# TODO: jam 20061219 Should this be a warning? A single line
1604
# warning might be sufficient to let the user know what
1606
mutter('Could not write hashcache for %s\nError: %s',
1607
self._hashcache.cache_file_name(), e)
1609
def set_conflicts(self, arg):
1610
raise errors.UnsupportedOperation(self.set_conflicts, self)
1612
def add_conflicts(self, arg):
1613
raise errors.UnsupportedOperation(self.add_conflicts, self)
1615
def conflicts(self):
1616
raise NotImplementedError(self.conflicts)
1618
def walkdirs(self, prefix=""):
1619
"""Walk the directories of this tree.
1621
returns a generator which yields items in the form:
1622
((curren_directory_path, fileid),
1623
[(file1_path, file1_name, file1_kind, (lstat), file1_id,
1626
This API returns a generator, which is only valid during the current
1627
tree transaction - within a single lock_read or lock_write duration.
1629
If the tree is not locked, it may cause an error to be raised,
1630
depending on the tree implementation.
1632
disk_top = self.abspath(prefix)
1633
if disk_top.endswith('/'):
1634
disk_top = disk_top[:-1]
1635
top_strip_len = len(disk_top) + 1
1636
inventory_iterator = self._walkdirs(prefix)
1637
disk_iterator = osutils.walkdirs(disk_top, prefix)
1639
current_disk = disk_iterator.next()
1640
disk_finished = False
1642
if not (e.errno == errno.ENOENT or
1643
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
1646
disk_finished = True
1648
current_inv = inventory_iterator.next()
1649
inv_finished = False
1650
except StopIteration:
1653
while not inv_finished or not disk_finished:
1655
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
1656
cur_disk_dir_content) = current_disk
1658
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
1659
cur_disk_dir_content) = ((None, None), None)
1660
if not disk_finished:
1661
# strip out .bzr dirs
1662
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
1663
len(cur_disk_dir_content) > 0):
1664
# osutils.walkdirs can be made nicer -
1665
# yield the path-from-prefix rather than the pathjoined
1667
bzrdir_loc = bisect_left(cur_disk_dir_content,
1669
if (bzrdir_loc < len(cur_disk_dir_content)
1670
and self.bzrdir.is_control_filename(
1671
cur_disk_dir_content[bzrdir_loc][0])):
1672
# we dont yield the contents of, or, .bzr itself.
1673
del cur_disk_dir_content[bzrdir_loc]
1675
# everything is unknown
1678
# everything is missing
1681
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
1683
# disk is before inventory - unknown
1684
dirblock = [(relpath, basename, kind, stat, None, None) for
1685
relpath, basename, kind, stat, top_path in
1686
cur_disk_dir_content]
1687
yield (cur_disk_dir_relpath, None), dirblock
1689
current_disk = disk_iterator.next()
1690
except StopIteration:
1691
disk_finished = True
1693
# inventory is before disk - missing.
1694
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
1695
for relpath, basename, dkind, stat, fileid, kind in
1697
yield (current_inv[0][0], current_inv[0][1]), dirblock
1699
current_inv = inventory_iterator.next()
1700
except StopIteration:
1703
# versioned present directory
1704
# merge the inventory and disk data together
1706
for relpath, subiterator in itertools.groupby(sorted(
1707
current_inv[1] + cur_disk_dir_content,
1708
key=operator.itemgetter(0)), operator.itemgetter(1)):
1709
path_elements = list(subiterator)
1710
if len(path_elements) == 2:
1711
inv_row, disk_row = path_elements
1712
# versioned, present file
1713
dirblock.append((inv_row[0],
1714
inv_row[1], disk_row[2],
1715
disk_row[3], inv_row[4],
1717
elif len(path_elements[0]) == 5:
1719
dirblock.append((path_elements[0][0],
1720
path_elements[0][1], path_elements[0][2],
1721
path_elements[0][3], None, None))
1722
elif len(path_elements[0]) == 6:
1723
# versioned, absent file.
1724
dirblock.append((path_elements[0][0],
1725
path_elements[0][1], 'unknown', None,
1726
path_elements[0][4], path_elements[0][5]))
1728
raise NotImplementedError('unreachable code')
1729
yield current_inv[0], dirblock
1731
current_inv = inventory_iterator.next()
1732
except StopIteration:
1735
current_disk = disk_iterator.next()
1736
except StopIteration:
1737
disk_finished = True
1739
def _walkdirs(self, prefix=""):
1740
"""Walk the directories of this tree.
1742
:param prefix: is used as the directrory to start with.
1743
:returns: a generator which yields items in the form::
1745
((curren_directory_path, fileid),
1746
[(file1_path, file1_name, file1_kind, None, file1_id,
1749
raise NotImplementedError(self._walkdirs)
1751
@needs_tree_write_lock
1752
def auto_resolve(self):
1753
"""Automatically resolve text conflicts according to contents.
1755
Only text conflicts are auto_resolvable. Files with no conflict markers
1756
are considered 'resolved', because bzr always puts conflict markers
1757
into files that have text conflicts. The corresponding .THIS .BASE and
1758
.OTHER files are deleted, as per 'resolve'.
1760
:return: a tuple of ConflictLists: (un_resolved, resolved).
1762
un_resolved = _mod_conflicts.ConflictList()
1763
resolved = _mod_conflicts.ConflictList()
1764
conflict_re = re.compile('^(<{7}|={7}|>{7})')
1765
for conflict in self.conflicts():
1766
if (conflict.typestring != 'text conflict' or
1767
self.kind(conflict.file_id) != 'file'):
1768
un_resolved.append(conflict)
1770
my_file = open(self.id2abspath(conflict.file_id), 'rb')
1772
for line in my_file:
1773
if conflict_re.search(line):
1774
un_resolved.append(conflict)
1777
resolved.append(conflict)
1780
resolved.remove_files(self)
1781
self.set_conflicts(un_resolved)
1782
return un_resolved, resolved
1784
def _validate(self):
1785
"""Validate internal structures.
1787
This is meant mostly for the test suite. To give it a chance to detect
1788
corruption after actions have occurred. The default implementation is a
1791
:return: None. An exception should be raised if there is an error.
1795
def check_state(self):
1796
"""Check that the working state is/isn't valid."""
1797
raise NotImplementedError(self.check_state)
1799
def reset_state(self, revision_ids=None):
1800
"""Reset the state of the working tree.
1802
This does a hard-reset to a last-known-good state. This is a way to
1803
fix if something got corrupted (like the .bzr/checkout/dirstate file)
1805
raise NotImplementedError(self.reset_state)
1807
def _get_rules_searcher(self, default_searcher):
1808
"""See Tree._get_rules_searcher."""
1809
if self._rules_searcher is None:
1810
self._rules_searcher = super(WorkingTree,
1811
self)._get_rules_searcher(default_searcher)
1812
return self._rules_searcher
1814
def get_shelf_manager(self):
1815
"""Return the ShelfManager for this WorkingTree."""
1816
from bzrlib.shelf import ShelfManager
1817
return ShelfManager(self, self._transport)
1820
class InventoryWorkingTree(WorkingTree,
1821
bzrlib.mutabletree.MutableInventoryTree):
1822
"""Base class for working trees that are inventory-oriented.
1824
The inventory is held in the `Branch` working-inventory, and the
1825
files are in a directory on disk.
1827
It is possible for a `WorkingTree` to have a filename which is
1828
not listed in the Inventory and vice versa.
1831
def __init__(self, basedir='.',
1832
branch=DEPRECATED_PARAMETER,
1834
_control_files=None,
1838
"""Construct a InventoryWorkingTree instance. This is not a public API.
1840
:param branch: A branch to override probing for the branch.
1842
super(InventoryWorkingTree, self).__init__(basedir=basedir,
1843
branch=branch, _control_files=_control_files, _internal=_internal,
1844
_format=_format, _bzrdir=_bzrdir)
1846
if _inventory is None:
1847
# This will be acquired on lock_read() or lock_write()
1848
self._inventory_is_modified = False
1849
self._inventory = None
1851
# the caller of __init__ has provided an inventory,
1852
# we assume they know what they are doing - as its only
1853
# the Format factory and creation methods that are
1854
# permitted to do this.
1855
self._set_inventory(_inventory, dirty=False)
1857
def _set_inventory(self, inv, dirty):
1858
"""Set the internal cached inventory.
1860
:param inv: The inventory to set.
1861
:param dirty: A boolean indicating whether the inventory is the same
1862
logical inventory as whats on disk. If True the inventory is not
1863
the same and should be written to disk or data will be lost, if
1864
False then the inventory is the same as that on disk and any
1865
serialisation would be unneeded overhead.
1867
self._inventory = inv
1868
self._inventory_is_modified = dirty
1870
def _serialize(self, inventory, out_file):
1871
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1874
def _deserialize(selt, in_file):
1875
return xml5.serializer_v5.read_inventory(in_file)
1877
@needs_tree_write_lock
1878
def _write_inventory(self, inv):
1879
"""Write inventory as the current inventory."""
1880
self._set_inventory(inv, dirty=True)
1883
# XXX: This method should be deprecated in favour of taking in a proper
1884
# new Inventory object.
1885
@needs_tree_write_lock
1886
def set_inventory(self, new_inventory_list):
1887
from bzrlib.inventory import (Inventory,
1891
inv = Inventory(self.get_root_id())
1892
for path, file_id, parent, kind in new_inventory_list:
1893
name = os.path.basename(path)
1896
# fixme, there should be a factory function inv,add_??
1897
if kind == 'directory':
1898
inv.add(InventoryDirectory(file_id, name, parent))
1899
elif kind == 'file':
1900
inv.add(InventoryFile(file_id, name, parent))
1901
elif kind == 'symlink':
1902
inv.add(InventoryLink(file_id, name, parent))
1904
raise errors.BzrError("unknown kind %r" % kind)
1905
self._write_inventory(inv)
1907
def _write_basis_inventory(self, xml):
1908
"""Write the basis inventory XML to the basis-inventory file"""
1909
path = self._basis_inventory_name()
1911
self._transport.put_file(path, sio,
1912
mode=self.bzrdir._get_file_mode())
1914
def _reset_data(self):
1915
"""Reset transient data that cannot be revalidated."""
1916
self._inventory_is_modified = False
1917
f = self._transport.get('inventory')
1919
result = self._deserialize(f)
1922
self._set_inventory(result, dirty=False)
1924
def _set_root_id(self, file_id):
1925
"""Set the root id for this tree, in a format specific manner.
1927
:param file_id: The file id to assign to the root. It must not be
1928
present in the current inventory or an error will occur. It must
1929
not be None, but rather a valid file id.
1931
inv = self._inventory
1932
orig_root_id = inv.root.file_id
1933
# TODO: it might be nice to exit early if there was nothing
1934
# to do, saving us from trigger a sync on unlock.
1935
self._inventory_is_modified = True
1936
# we preserve the root inventory entry object, but
1937
# unlinkit from the byid index
1938
del inv._byid[inv.root.file_id]
1939
inv.root.file_id = file_id
1940
# and link it into the index with the new changed id.
1941
inv._byid[inv.root.file_id] = inv.root
1942
# and finally update all children to reference the new id.
1943
# XXX: this should be safe to just look at the root.children
1944
# list, not the WHOLE INVENTORY.
1947
if entry.parent_id == orig_root_id:
1948
entry.parent_id = inv.root.file_id
1950
def all_file_ids(self):
1951
"""See Tree.iter_all_file_ids"""
1952
return set(self.inventory)
1954
@needs_tree_write_lock
1955
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
1956
"""See MutableTree.set_parent_trees."""
1957
parent_ids = [rev for (rev, tree) in parents_list]
1958
for revision_id in parent_ids:
1959
_mod_revision.check_not_reserved_id(revision_id)
1961
self._check_parents_for_ghosts(parent_ids,
1962
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
1964
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
1966
if len(parent_ids) == 0:
1967
leftmost_parent_id = _mod_revision.NULL_REVISION
1968
leftmost_parent_tree = None
1970
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
1972
if self._change_last_revision(leftmost_parent_id):
1973
if leftmost_parent_tree is None:
1974
# If we don't have a tree, fall back to reading the
1975
# parent tree from the repository.
1976
self._cache_basis_inventory(leftmost_parent_id)
1978
inv = leftmost_parent_tree.inventory
1979
xml = self._create_basis_xml_from_inventory(
1980
leftmost_parent_id, inv)
1981
self._write_basis_inventory(xml)
1982
self._set_merges_from_parent_ids(parent_ids)
1984
def _cache_basis_inventory(self, new_revision):
1985
"""Cache new_revision as the basis inventory."""
1986
# TODO: this should allow the ready-to-use inventory to be passed in,
1987
# as commit already has that ready-to-use [while the format is the
1990
# this double handles the inventory - unpack and repack -
1991
# but is easier to understand. We can/should put a conditional
1992
# in here based on whether the inventory is in the latest format
1993
# - perhaps we should repack all inventories on a repository
1995
# the fast path is to copy the raw xml from the repository. If the
1996
# xml contains 'revision_id="', then we assume the right
1997
# revision_id is set. We must check for this full string, because a
1998
# root node id can legitimately look like 'revision_id' but cannot
2000
xml = self.branch.repository._get_inventory_xml(new_revision)
2001
firstline = xml.split('\n', 1)[0]
2002
if (not 'revision_id="' in firstline or
2003
'format="7"' not in firstline):
2004
inv = self.branch.repository._serializer.read_inventory_from_string(
2006
xml = self._create_basis_xml_from_inventory(new_revision, inv)
2007
self._write_basis_inventory(xml)
2008
except (errors.NoSuchRevision, errors.RevisionNotPresent):
2011
def _basis_inventory_name(self):
2012
return 'basis-inventory-cache'
2014
def _create_basis_xml_from_inventory(self, revision_id, inventory):
2015
"""Create the text that will be saved in basis-inventory"""
2016
inventory.revision_id = revision_id
2017
return xml7.serializer_v7.write_inventory_to_string(inventory)
2019
@needs_tree_write_lock
2020
def set_conflicts(self, conflicts):
2021
self._put_rio('conflicts', conflicts.to_stanzas(),
2024
@needs_tree_write_lock
2025
def add_conflicts(self, new_conflicts):
2026
conflict_set = set(self.conflicts())
2027
conflict_set.update(set(list(new_conflicts)))
2028
self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
2029
key=_mod_conflicts.Conflict.sort_key)))
2032
def conflicts(self):
2034
confile = self._transport.get('conflicts')
2035
except errors.NoSuchFile:
2036
return _mod_conflicts.ConflictList()
2039
if confile.next() != CONFLICT_HEADER_1 + '\n':
2040
raise errors.ConflictFormatError()
2041
except StopIteration:
2042
raise errors.ConflictFormatError()
2043
reader = _mod_rio.RioReader(confile)
2044
return _mod_conflicts.ConflictList.from_stanzas(reader)
2048
def read_basis_inventory(self):
2049
"""Read the cached basis inventory."""
2050
path = self._basis_inventory_name()
2051
return self._transport.get_bytes(path)
2054
def read_working_inventory(self):
2055
"""Read the working inventory.
2057
:raises errors.InventoryModified: read_working_inventory will fail
2058
when the current in memory inventory has been modified.
2060
# conceptually this should be an implementation detail of the tree.
2061
# XXX: Deprecate this.
2062
# ElementTree does its own conversion from UTF-8, so open in
2064
if self._inventory_is_modified:
2065
raise errors.InventoryModified(self)
2066
f = self._transport.get('inventory')
2068
result = self._deserialize(f)
2071
self._set_inventory(result, dirty=False)
2075
def get_root_id(self):
2076
"""Return the id of this trees root"""
2077
return self._inventory.root.file_id
2079
def has_id(self, file_id):
2080
# files that have been deleted are excluded
2081
inv = self.inventory
2082
if not inv.has_id(file_id):
2084
path = inv.id2path(file_id)
2085
return osutils.lexists(self.abspath(path))
2087
def has_or_had_id(self, file_id):
2088
if file_id == self.inventory.root.file_id:
2090
return self.inventory.has_id(file_id)
2092
__contains__ = has_id
2094
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2096
"""Iterate through file_ids for this tree.
2098
file_ids are in a WorkingTree if they are in the working inventory
2099
and the working file exists.
2101
inv = self._inventory
2102
for path, ie in inv.iter_entries():
2103
if osutils.lexists(self.abspath(path)):
2106
@needs_tree_write_lock
2107
def set_last_revision(self, new_revision):
2108
"""Change the last revision in the working tree."""
2109
if self._change_last_revision(new_revision):
2110
self._cache_basis_inventory(new_revision)
2112
def _get_check_refs(self):
2113
"""Return the references needed to perform a check of this tree.
2115
The default implementation returns no refs, and is only suitable for
2116
trees that have no local caching and can commit on ghosts at any time.
2118
:seealso: bzrlib.check for details about check_refs.
2123
def _check(self, references):
2124
"""Check the tree for consistency.
2126
:param references: A dict with keys matching the items returned by
2127
self._get_check_refs(), and values from looking those keys up in
2130
tree_basis = self.basis_tree()
2131
tree_basis.lock_read()
2133
repo_basis = references[('trees', self.last_revision())]
2134
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2135
raise errors.BzrCheckError(
2136
"Mismatched basis inventory content.")
2142
def check_state(self):
2143
"""Check that the working state is/isn't valid."""
2144
check_refs = self._get_check_refs()
2146
for ref in check_refs:
2149
refs[ref] = self.branch.repository.revision_tree(value)
2152
@needs_tree_write_lock
2153
def reset_state(self, revision_ids=None):
2154
"""Reset the state of the working tree.
2156
This does a hard-reset to a last-known-good state. This is a way to
2157
fix if something got corrupted (like the .bzr/checkout/dirstate file)
2159
if revision_ids is None:
2160
revision_ids = self.get_parent_ids()
2161
if not revision_ids:
2162
rt = self.branch.repository.revision_tree(
2163
_mod_revision.NULL_REVISION)
2165
rt = self.branch.repository.revision_tree(revision_ids[0])
2166
self._write_inventory(rt.inventory)
2167
self.set_parent_ids(revision_ids)
2170
"""Write the in memory inventory to disk."""
2171
# TODO: Maybe this should only write on dirty ?
2172
if self._control_files._lock_mode != 'w':
2173
raise errors.NotWriteLocked(self)
2175
self._serialize(self._inventory, sio)
2177
self._transport.put_file('inventory', sio,
2178
mode=self.bzrdir._get_file_mode())
2179
self._inventory_is_modified = False
2182
def get_file_sha1(self, file_id, path=None, stat_value=None):
2184
path = self._inventory.id2path(file_id)
2185
return self._hashcache.get_sha1(path, stat_value)
2187
def get_file_mtime(self, file_id, path=None):
2188
"""See Tree.get_file_mtime."""
2190
path = self.inventory.id2path(file_id)
2191
return os.lstat(self.abspath(path)).st_mtime
2193
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2194
file_id = self.path2id(path)
2196
# For unversioned files on win32, we just assume they are not
2199
return self._inventory[file_id].executable
2201
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2202
mode = stat_result.st_mode
2203
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2205
if not supports_executable():
2206
def is_executable(self, file_id, path=None):
2207
return self._inventory[file_id].executable
2209
_is_executable_from_path_and_stat = \
2210
_is_executable_from_path_and_stat_from_basis
2212
def is_executable(self, file_id, path=None):
2214
path = self.id2path(file_id)
2215
mode = os.lstat(self.abspath(path)).st_mode
2216
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2218
_is_executable_from_path_and_stat = \
2219
_is_executable_from_path_and_stat_from_stat
2221
@needs_tree_write_lock
2222
def _add(self, files, ids, kinds):
2223
"""See MutableTree._add."""
2224
# TODO: Re-adding a file that is removed in the working copy
2225
# should probably put it back with the previous ID.
2226
# the read and write working inventory should not occur in this
2227
# function - they should be part of lock_write and unlock.
2228
inv = self.inventory
2229
for f, file_id, kind in zip(files, ids, kinds):
2231
inv.add_path(f, kind=kind)
2233
inv.add_path(f, kind=kind, file_id=file_id)
2234
self._inventory_is_modified = True
2236
def revision_tree(self, revision_id):
2237
"""See WorkingTree.revision_id."""
2238
if revision_id == self.last_revision():
2240
xml = self.read_basis_inventory()
2241
except errors.NoSuchFile:
2245
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2246
# dont use the repository revision_tree api because we want
2247
# to supply the inventory.
2248
if inv.revision_id == revision_id:
2249
return revisiontree.InventoryRevisionTree(
2250
self.branch.repository, inv, revision_id)
2251
except errors.BadInventoryFormat:
2253
# raise if there was no inventory, or if we read the wrong inventory.
2254
raise errors.NoSuchRevisionInTree(self, revision_id)
2257
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
2258
"""See Tree.annotate_iter
2260
This implementation will use the basis tree implementation if possible.
2261
Lines not in the basis are attributed to CURRENT_REVISION
2263
If there are pending merges, lines added by those merges will be
2264
incorrectly attributed to CURRENT_REVISION (but after committing, the
2265
attribution will be correct).
2267
maybe_file_parent_keys = []
2268
for parent_id in self.get_parent_ids():
2270
parent_tree = self.revision_tree(parent_id)
2271
except errors.NoSuchRevisionInTree:
2272
parent_tree = self.branch.repository.revision_tree(parent_id)
2273
parent_tree.lock_read()
2275
if file_id not in parent_tree:
2277
ie = parent_tree.inventory[file_id]
2278
if ie.kind != 'file':
2279
# Note: this is slightly unnecessary, because symlinks and
2280
# directories have a "text" which is the empty text, and we
2281
# know that won't mess up annotations. But it seems cleaner
2283
parent_text_key = (file_id, ie.revision)
2284
if parent_text_key not in maybe_file_parent_keys:
2285
maybe_file_parent_keys.append(parent_text_key)
2287
parent_tree.unlock()
2288
graph = _mod_graph.Graph(self.branch.repository.texts)
2289
heads = graph.heads(maybe_file_parent_keys)
2290
file_parent_keys = []
2291
for key in maybe_file_parent_keys:
2293
file_parent_keys.append(key)
2295
# Now we have the parents of this content
2296
annotator = self.branch.repository.texts.get_annotator()
2297
text = self.get_file_text(file_id)
2298
this_key =(file_id, default_revision)
2299
annotator.add_special_text(this_key, file_parent_keys, text)
2300
annotations = [(key[-1], line)
2301
for key, line in annotator.annotate_flat(this_key)]
2305
def merge_modified(self):
2306
"""Return a dictionary of files modified by a merge.
2308
The list is initialized by WorkingTree.set_merge_modified, which is
2309
typically called after we make some automatic updates to the tree
2312
This returns a map of file_id->sha1, containing only files which are
2313
still in the working inventory and have that text hash.
2316
hashfile = self._transport.get('merge-hashes')
2317
except errors.NoSuchFile:
2322
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
2323
raise errors.MergeModifiedFormatError()
2324
except StopIteration:
2325
raise errors.MergeModifiedFormatError()
2326
for s in _mod_rio.RioReader(hashfile):
2327
# RioReader reads in Unicode, so convert file_ids back to utf8
2328
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2329
if file_id not in self.inventory:
2331
text_hash = s.get("hash")
2332
if text_hash == self.get_file_sha1(file_id):
2333
merge_hashes[file_id] = text_hash
2339
def subsume(self, other_tree):
2340
def add_children(inventory, entry):
2341
for child_entry in entry.children.values():
2342
inventory._byid[child_entry.file_id] = child_entry
2343
if child_entry.kind == 'directory':
2344
add_children(inventory, child_entry)
2345
if other_tree.get_root_id() == self.get_root_id():
2346
raise errors.BadSubsumeSource(self, other_tree,
2347
'Trees have the same root')
2349
other_tree_path = self.relpath(other_tree.basedir)
2350
except errors.PathNotChild:
2351
raise errors.BadSubsumeSource(self, other_tree,
2352
'Tree is not contained by the other')
2353
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
2354
if new_root_parent is None:
2355
raise errors.BadSubsumeSource(self, other_tree,
2356
'Parent directory is not versioned.')
2357
# We need to ensure that the result of a fetch will have a
2358
# versionedfile for the other_tree root, and only fetching into
2359
# RepositoryKnit2 guarantees that.
2360
if not self.branch.repository.supports_rich_root():
2361
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
2362
other_tree.lock_tree_write()
2364
new_parents = other_tree.get_parent_ids()
2365
other_root = other_tree.inventory.root
2366
other_root.parent_id = new_root_parent
2367
other_root.name = osutils.basename(other_tree_path)
2368
self.inventory.add(other_root)
2369
add_children(self.inventory, other_root)
2370
self._write_inventory(self.inventory)
2371
# normally we don't want to fetch whole repositories, but i think
2372
# here we really do want to consolidate the whole thing.
2373
for parent_id in other_tree.get_parent_ids():
2374
self.branch.fetch(other_tree.branch, parent_id)
2375
self.add_parent_tree_id(parent_id)
2378
other_tree.bzrdir.retire_bzrdir()
2380
@needs_tree_write_lock
2381
def extract(self, file_id, format=None):
2382
"""Extract a subtree from this tree.
2384
A new branch will be created, relative to the path for this tree.
2388
segments = osutils.splitpath(path)
2389
transport = self.branch.bzrdir.root_transport
2390
for name in segments:
2391
transport = transport.clone(name)
2392
transport.ensure_base()
2395
sub_path = self.id2path(file_id)
2396
branch_transport = mkdirs(sub_path)
2398
format = self.bzrdir.cloning_metadir()
2399
branch_transport.ensure_base()
2400
branch_bzrdir = format.initialize_on_transport(branch_transport)
2402
repo = branch_bzrdir.find_repository()
2403
except errors.NoRepositoryPresent:
2404
repo = branch_bzrdir.create_repository()
2405
if not repo.supports_rich_root():
2406
raise errors.RootNotRich()
2407
new_branch = branch_bzrdir.create_branch()
2408
new_branch.pull(self.branch)
2409
for parent_id in self.get_parent_ids():
2410
new_branch.fetch(self.branch, parent_id)
2411
tree_transport = self.bzrdir.root_transport.clone(sub_path)
2412
if tree_transport.base != branch_transport.base:
2413
tree_bzrdir = format.initialize_on_transport(tree_transport)
2414
branch.BranchReferenceFormat().initialize(tree_bzrdir,
2415
target_branch=new_branch)
2417
tree_bzrdir = branch_bzrdir
2418
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2419
wt.set_parent_ids(self.get_parent_ids())
2420
my_inv = self.inventory
2421
child_inv = inventory.Inventory(root_id=None)
2422
new_root = my_inv[file_id]
2423
my_inv.remove_recursive_id(file_id)
2424
new_root.parent_id = None
2425
child_inv.add(new_root)
2426
self._write_inventory(my_inv)
2427
wt._write_inventory(child_inv)
2430
def list_files(self, include_root=False, from_dir=None, recursive=True):
2431
"""List all files as (path, class, kind, id, entry).
2433
Lists, but does not descend into unversioned directories.
2434
This does not include files that have been deleted in this
2435
tree. Skips the control directory.
2437
:param include_root: if True, return an entry for the root
2438
:param from_dir: start from this directory or None for the root
2439
:param recursive: whether to recurse into subdirectories or not
2441
# list_files is an iterator, so @needs_read_lock doesn't work properly
2442
# with it. So callers should be careful to always read_lock the tree.
2443
if not self.is_locked():
2444
raise errors.ObjectNotLocked(self)
2446
inv = self.inventory
2447
if from_dir is None and include_root is True:
2448
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
2449
# Convert these into local objects to save lookup times
2450
pathjoin = osutils.pathjoin
2451
file_kind = self._kind
2453
# transport.base ends in a slash, we want the piece
2454
# between the last two slashes
2455
transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
2457
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
2459
# directory file_id, relative path, absolute path, reverse sorted children
2460
if from_dir is not None:
2461
from_dir_id = inv.path2id(from_dir)
2462
if from_dir_id is None:
2463
# Directory not versioned
2465
from_dir_abspath = pathjoin(self.basedir, from_dir)
2467
from_dir_id = inv.root.file_id
2468
from_dir_abspath = self.basedir
2469
children = os.listdir(from_dir_abspath)
2471
# jam 20060527 The kernel sized tree seems equivalent whether we
2472
# use a deque and popleft to keep them sorted, or if we use a plain
2473
# list and just reverse() them.
2474
children = collections.deque(children)
2475
stack = [(from_dir_id, u'', from_dir_abspath, children)]
2477
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
2480
f = children.popleft()
2481
## TODO: If we find a subdirectory with its own .bzr
2482
## directory, then that is a separate tree and we
2483
## should exclude it.
2485
# the bzrdir for this tree
2486
if transport_base_dir == f:
2489
# we know that from_dir_relpath and from_dir_abspath never end in a slash
2490
# and 'f' doesn't begin with one, we can do a string op, rather
2491
# than the checks of pathjoin(), all relative paths will have an extra slash
2493
fp = from_dir_relpath + '/' + f
2496
fap = from_dir_abspath + '/' + f
2498
dir_ie = inv[from_dir_id]
2499
if dir_ie.kind == 'directory':
2500
f_ie = dir_ie.children.get(f)
2505
elif self.is_ignored(fp[1:]):
2508
# we may not have found this file, because of a unicode
2509
# issue, or because the directory was actually a symlink.
2510
f_norm, can_access = osutils.normalized_filename(f)
2511
if f == f_norm or not can_access:
2512
# No change, so treat this file normally
2515
# this file can be accessed by a normalized path
2516
# check again if it is versioned
2517
# these lines are repeated here for performance
2519
fp = from_dir_relpath + '/' + f
2520
fap = from_dir_abspath + '/' + f
2521
f_ie = inv.get_child(from_dir_id, f)
2524
elif self.is_ignored(fp[1:]):
2531
# make a last minute entry
2533
yield fp[1:], c, fk, f_ie.file_id, f_ie
2536
yield fp[1:], c, fk, None, fk_entries[fk]()
2538
yield fp[1:], c, fk, None, TreeEntry()
2541
if fk != 'directory':
2544
# But do this child first if recursing down
2546
new_children = os.listdir(fap)
2548
new_children = collections.deque(new_children)
2549
stack.append((f_ie.file_id, fp, fap, new_children))
2550
# Break out of inner loop,
2551
# so that we start outer loop with child
2554
# if we finished all children, pop it off the stack
2557
@needs_tree_write_lock
2558
def move(self, from_paths, to_dir=None, after=False):
2561
to_dir must exist in the inventory.
2563
If to_dir exists and is a directory, the files are moved into
2564
it, keeping their old names.
2566
Note that to_dir is only the last component of the new name;
2567
this doesn't change the directory.
2569
For each entry in from_paths the move mode will be determined
2572
The first mode moves the file in the filesystem and updates the
2573
inventory. The second mode only updates the inventory without
2574
touching the file on the filesystem.
2576
move uses the second mode if 'after == True' and the target is not
2577
versioned but present in the working tree.
2579
move uses the second mode if 'after == False' and the source is
2580
versioned but no longer in the working tree, and the target is not
2581
versioned but present in the working tree.
2583
move uses the first mode if 'after == False' and the source is
2584
versioned and present in the working tree, and the target is not
2585
versioned and not present in the working tree.
2587
Everything else results in an error.
2589
This returns a list of (from_path, to_path) pairs for each
2590
entry that is moved.
2595
# check for deprecated use of signature
2597
raise TypeError('You must supply a target directory')
2598
# check destination directory
2599
if isinstance(from_paths, basestring):
2601
inv = self.inventory
2602
to_abs = self.abspath(to_dir)
2603
if not isdir(to_abs):
2604
raise errors.BzrMoveFailedError('',to_dir,
2605
errors.NotADirectory(to_abs))
2606
if not self.has_filename(to_dir):
2607
raise errors.BzrMoveFailedError('',to_dir,
2608
errors.NotInWorkingDirectory(to_dir))
2609
to_dir_id = inv.path2id(to_dir)
2610
if to_dir_id is None:
2611
raise errors.BzrMoveFailedError('',to_dir,
2612
errors.NotVersionedError(path=to_dir))
2614
to_dir_ie = inv[to_dir_id]
2615
if to_dir_ie.kind != 'directory':
2616
raise errors.BzrMoveFailedError('',to_dir,
2617
errors.NotADirectory(to_abs))
2619
# create rename entries and tuples
2620
for from_rel in from_paths:
2621
from_tail = splitpath(from_rel)[-1]
2622
from_id = inv.path2id(from_rel)
2624
raise errors.BzrMoveFailedError(from_rel,to_dir,
2625
errors.NotVersionedError(path=from_rel))
2627
from_entry = inv[from_id]
2628
from_parent_id = from_entry.parent_id
2629
to_rel = pathjoin(to_dir, from_tail)
2630
rename_entry = InventoryWorkingTree._RenameEntry(
2633
from_tail=from_tail,
2634
from_parent_id=from_parent_id,
2635
to_rel=to_rel, to_tail=from_tail,
2636
to_parent_id=to_dir_id)
2637
rename_entries.append(rename_entry)
2638
rename_tuples.append((from_rel, to_rel))
2640
# determine which move mode to use. checks also for movability
2641
rename_entries = self._determine_mv_mode(rename_entries, after)
2643
original_modified = self._inventory_is_modified
2646
self._inventory_is_modified = True
2647
self._move(rename_entries)
2649
# restore the inventory on error
2650
self._inventory_is_modified = original_modified
2652
self._write_inventory(inv)
2653
return rename_tuples
2655
@needs_tree_write_lock
2656
def rename_one(self, from_rel, to_rel, after=False):
2659
This can change the directory or the filename or both.
2661
rename_one has several 'modes' to work. First, it can rename a physical
2662
file and change the file_id. That is the normal mode. Second, it can
2663
only change the file_id without touching any physical file.
2665
rename_one uses the second mode if 'after == True' and 'to_rel' is not
2666
versioned but present in the working tree.
2668
rename_one uses the second mode if 'after == False' and 'from_rel' is
2669
versioned but no longer in the working tree, and 'to_rel' is not
2670
versioned but present in the working tree.
2672
rename_one uses the first mode if 'after == False' and 'from_rel' is
2673
versioned and present in the working tree, and 'to_rel' is not
2674
versioned and not present in the working tree.
2676
Everything else results in an error.
2678
inv = self.inventory
2681
# create rename entries and tuples
2682
from_tail = splitpath(from_rel)[-1]
2683
from_id = inv.path2id(from_rel)
2685
# if file is missing in the inventory maybe it's in the basis_tree
2686
basis_tree = self.branch.basis_tree()
2687
from_id = basis_tree.path2id(from_rel)
2689
raise errors.BzrRenameFailedError(from_rel,to_rel,
2690
errors.NotVersionedError(path=from_rel))
2691
# put entry back in the inventory so we can rename it
2692
from_entry = basis_tree.inventory[from_id].copy()
2695
from_entry = inv[from_id]
2696
from_parent_id = from_entry.parent_id
2697
to_dir, to_tail = os.path.split(to_rel)
2698
to_dir_id = inv.path2id(to_dir)
2699
rename_entry = InventoryWorkingTree._RenameEntry(from_rel=from_rel,
2701
from_tail=from_tail,
2702
from_parent_id=from_parent_id,
2703
to_rel=to_rel, to_tail=to_tail,
2704
to_parent_id=to_dir_id)
2705
rename_entries.append(rename_entry)
2707
# determine which move mode to use. checks also for movability
2708
rename_entries = self._determine_mv_mode(rename_entries, after)
2710
# check if the target changed directory and if the target directory is
2712
if to_dir_id is None:
2713
raise errors.BzrMoveFailedError(from_rel,to_rel,
2714
errors.NotVersionedError(path=to_dir))
2716
# all checks done. now we can continue with our actual work
2717
mutter('rename_one:\n'
2722
' to_dir_id {%s}\n',
2723
from_id, from_rel, to_rel, to_dir, to_dir_id)
2725
self._move(rename_entries)
2726
self._write_inventory(inv)
2728
class _RenameEntry(object):
2729
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2730
to_rel, to_tail, to_parent_id, only_change_inv=False):
2731
self.from_rel = from_rel
2732
self.from_id = from_id
2733
self.from_tail = from_tail
2734
self.from_parent_id = from_parent_id
2735
self.to_rel = to_rel
2736
self.to_tail = to_tail
2737
self.to_parent_id = to_parent_id
2738
self.only_change_inv = only_change_inv
2740
def _determine_mv_mode(self, rename_entries, after=False):
2741
"""Determines for each from-to pair if both inventory and working tree
2742
or only the inventory has to be changed.
2744
Also does basic plausability tests.
2746
inv = self.inventory
2748
for rename_entry in rename_entries:
2749
# store to local variables for easier reference
2750
from_rel = rename_entry.from_rel
2751
from_id = rename_entry.from_id
2752
to_rel = rename_entry.to_rel
2753
to_id = inv.path2id(to_rel)
2754
only_change_inv = False
2756
# check the inventory for source and destination
2758
raise errors.BzrMoveFailedError(from_rel,to_rel,
2759
errors.NotVersionedError(path=from_rel))
2760
if to_id is not None:
2761
raise errors.BzrMoveFailedError(from_rel,to_rel,
2762
errors.AlreadyVersionedError(path=to_rel))
2764
# try to determine the mode for rename (only change inv or change
2765
# inv and file system)
2767
if not self.has_filename(to_rel):
2768
raise errors.BzrMoveFailedError(from_id,to_rel,
2769
errors.NoSuchFile(path=to_rel,
2770
extra="New file has not been created yet"))
2771
only_change_inv = True
2772
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
2773
only_change_inv = True
2774
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
2775
only_change_inv = False
2776
elif (not self.case_sensitive
2777
and from_rel.lower() == to_rel.lower()
2778
and self.has_filename(from_rel)):
2779
only_change_inv = False
2781
# something is wrong, so lets determine what exactly
2782
if not self.has_filename(from_rel) and \
2783
not self.has_filename(to_rel):
2784
raise errors.BzrRenameFailedError(from_rel,to_rel,
2785
errors.PathsDoNotExist(paths=(str(from_rel),
2788
raise errors.RenameFailedFilesExist(from_rel, to_rel)
2789
rename_entry.only_change_inv = only_change_inv
2790
return rename_entries
2792
def _move(self, rename_entries):
2793
"""Moves a list of files.
2795
Depending on the value of the flag 'only_change_inv', the
2796
file will be moved on the file system or not.
2798
inv = self.inventory
2801
for entry in rename_entries:
2803
self._move_entry(entry)
2805
self._rollback_move(moved)
2809
def _rollback_move(self, moved):
2810
"""Try to rollback a previous move in case of an filesystem error."""
2811
inv = self.inventory
2814
self._move_entry(WorkingTree._RenameEntry(
2815
entry.to_rel, entry.from_id,
2816
entry.to_tail, entry.to_parent_id, entry.from_rel,
2817
entry.from_tail, entry.from_parent_id,
2818
entry.only_change_inv))
2819
except errors.BzrMoveFailedError, e:
2820
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
2821
" The working tree is in an inconsistent state."
2822
" Please consider doing a 'bzr revert'."
2823
" Error message is: %s" % e)
2825
def _move_entry(self, entry):
2826
inv = self.inventory
2827
from_rel_abs = self.abspath(entry.from_rel)
2828
to_rel_abs = self.abspath(entry.to_rel)
2829
if from_rel_abs == to_rel_abs:
2830
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
2831
"Source and target are identical.")
2833
if not entry.only_change_inv:
2835
osutils.rename(from_rel_abs, to_rel_abs)
2837
raise errors.BzrMoveFailedError(entry.from_rel,
2839
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
2841
@needs_tree_write_lock
2842
def unversion(self, file_ids):
2843
"""Remove the file ids in file_ids from the current versioned set.
2845
When a file_id is unversioned, all of its children are automatically
2848
:param file_ids: The file ids to stop versioning.
2849
:raises: NoSuchId if any fileid is not currently versioned.
2851
for file_id in file_ids:
2852
if file_id not in self._inventory:
2853
raise errors.NoSuchId(self, file_id)
2854
for file_id in file_ids:
2855
if self._inventory.has_id(file_id):
2856
self._inventory.remove_recursive_id(file_id)
2858
# in the future this should just set a dirty bit to wait for the
2859
# final unlock. However, until all methods of workingtree start
2860
# with the current in -memory inventory rather than triggering
2861
# a read, it is more complex - we need to teach read_inventory
2862
# to know when to read, and when to not read first... and possibly
2863
# to save first when the in memory one may be corrupted.
2864
# so for now, we just only write it if it is indeed dirty.
2866
self._write_inventory(self._inventory)
2868
def stored_kind(self, file_id):
2869
"""See Tree.stored_kind"""
2870
return self.inventory[file_id].kind
2873
"""Yield all unversioned files in this WorkingTree.
2875
If there are any unversioned directories then only the directory is
2876
returned, not all its children. But if there are unversioned files
2877
under a versioned subdirectory, they are returned.
2879
Currently returned depth-first, sorted by name within directories.
2880
This is the same order used by 'osutils.walkdirs'.
2882
## TODO: Work from given directory downwards
2883
for path, dir_entry in self.inventory.directories():
2884
# mutter("search for unknowns in %r", path)
2885
dirabs = self.abspath(path)
2886
if not isdir(dirabs):
2887
# e.g. directory deleted
2891
for subf in os.listdir(dirabs):
2892
if self.bzrdir.is_control_filename(subf):
2894
if subf not in dir_entry.children:
2897
can_access) = osutils.normalized_filename(subf)
2898
except UnicodeDecodeError:
2899
path_os_enc = path.encode(osutils._fs_enc)
2900
relpath = path_os_enc + '/' + subf
2901
raise errors.BadFilenameEncoding(relpath,
2903
if subf_norm != subf and can_access:
2904
if subf_norm not in dir_entry.children:
2905
fl.append(subf_norm)
2911
subp = pathjoin(path, subf)
2914
def _walkdirs(self, prefix=""):
2915
"""Walk the directories of this tree.
2917
:param prefix: is used as the directrory to start with.
2918
:returns: a generator which yields items in the form::
2920
((curren_directory_path, fileid),
2921
[(file1_path, file1_name, file1_kind, None, file1_id,
2924
_directory = 'directory'
2925
# get the root in the inventory
2926
inv = self.inventory
2927
top_id = inv.path2id(prefix)
2931
pending = [(prefix, '', _directory, None, top_id, None)]
2934
currentdir = pending.pop()
2935
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2936
top_id = currentdir[4]
2938
relroot = currentdir[0] + '/'
2941
# FIXME: stash the node in pending
2943
if entry.kind == 'directory':
2944
for name, child in entry.sorted_children():
2945
dirblock.append((relroot + name, name, child.kind, None,
2946
child.file_id, child.kind
2948
yield (currentdir[0], entry.file_id), dirblock
2949
# push the user specified dirs from dirblock
2950
for dir in reversed(dirblock):
2951
if dir[2] == _directory:
2955
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2956
"""Registry for working tree formats."""
2958
def __init__(self, other_registry=None):
2959
super(WorkingTreeFormatRegistry, self).__init__(other_registry)
2960
self._default_format = None
2961
self._default_format_key = None
2963
def get_default(self):
2964
"""Return the current default format."""
2965
if (self._default_format_key is not None and
2966
self._default_format is None):
2967
self._default_format = self.get(self._default_format_key)
2968
return self._default_format
2970
def set_default(self, format):
2971
"""Set the default format."""
2972
self._default_format = format
2973
self._default_format_key = None
2975
def set_default_key(self, format_string):
2976
"""Set the default format by its format string."""
2977
self._default_format_key = format_string
2978
self._default_format = None
2981
format_registry = WorkingTreeFormatRegistry()
2984
class WorkingTreeFormat(controldir.ControlComponentFormat):
2985
"""An encapsulation of the initialization and open routines for a format.
2987
Formats provide three things:
2988
* An initialization routine,
2992
Formats are placed in an dict by their format string for reference
2993
during workingtree opening. Its not required that these be instances, they
2994
can be classes themselves with class methods - it simply depends on
2995
whether state is needed for a given format or not.
2997
Once a format is deprecated, just deprecate the initialize and open
2998
methods on the format class. Do not deprecate the object, as the
2999
object will be created every time regardless.
3002
requires_rich_root = False
3004
upgrade_recommended = False
3006
requires_normalized_unicode_filenames = False
3008
case_sensitive_filename = "FoRMaT"
3010
missing_parent_conflicts = False
3011
"""If this format supports missing parent conflicts."""
3014
def find_format_string(klass, a_bzrdir):
3015
"""Return format name for the working tree object in a_bzrdir."""
3017
transport = a_bzrdir.get_workingtree_transport(None)
3018
return transport.get_bytes("format")
3019
except errors.NoSuchFile:
3020
raise errors.NoWorkingTree(base=transport.base)
3023
def find_format(klass, a_bzrdir):
3024
"""Return the format for the working tree object in a_bzrdir."""
3026
format_string = klass.find_format_string(a_bzrdir)
3027
return format_registry.get(format_string)
3029
raise errors.UnknownFormatError(format=format_string,
3030
kind="working tree")
3032
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3033
accelerator_tree=None, hardlink=False):
3034
"""Initialize a new working tree in a_bzrdir.
3036
:param a_bzrdir: BzrDir to initialize the working tree in.
3037
:param revision_id: allows creating a working tree at a different
3038
revision than the branch is at.
3039
:param from_branch: Branch to checkout
3040
:param accelerator_tree: A tree which can be used for retrieving file
3041
contents more quickly than the revision tree, i.e. a workingtree.
3042
The revision tree will be used for cases where accelerator_tree's
3043
content is different.
3044
:param hardlink: If true, hard-link files from accelerator_tree,
3047
raise NotImplementedError(self.initialize)
3049
def __eq__(self, other):
3050
return self.__class__ is other.__class__
3052
def __ne__(self, other):
3053
return not (self == other)
3056
@symbol_versioning.deprecated_method(
3057
symbol_versioning.deprecated_in((2, 4, 0)))
3058
def get_default_format(klass):
3059
"""Return the current default format."""
3060
return format_registry.get_default()
3062
def get_format_string(self):
3063
"""Return the ASCII format string that identifies this format."""
3064
raise NotImplementedError(self.get_format_string)
3066
def get_format_description(self):
3067
"""Return the short description for this format."""
3068
raise NotImplementedError(self.get_format_description)
3070
def is_supported(self):
3071
"""Is this format supported?
3073
Supported formats can be initialized and opened.
3074
Unsupported formats may not support initialization or committing or
3075
some other features depending on the reason for not being supported.
3079
def supports_content_filtering(self):
3080
"""True if this format supports content filtering."""
3083
def supports_views(self):
3084
"""True if this format supports stored views."""
3088
@symbol_versioning.deprecated_method(
3089
symbol_versioning.deprecated_in((2, 4, 0)))
3090
def register_format(klass, format):
3091
format_registry.register(format)
3094
@symbol_versioning.deprecated_method(
3095
symbol_versioning.deprecated_in((2, 4, 0)))
3096
def register_extra_format(klass, format):
3097
format_registry.register_extra(format)
3100
@symbol_versioning.deprecated_method(
3101
symbol_versioning.deprecated_in((2, 4, 0)))
3102
def unregister_extra_format(klass, format):
3103
format_registry.unregister_extra(format)
3106
@symbol_versioning.deprecated_method(
3107
symbol_versioning.deprecated_in((2, 4, 0)))
3108
def get_formats(klass):
3109
return format_registry._get_all()
3112
@symbol_versioning.deprecated_method(
3113
symbol_versioning.deprecated_in((2, 4, 0)))
3114
def set_default_format(klass, format):
3115
format_registry.set_default(format)
3118
@symbol_versioning.deprecated_method(
3119
symbol_versioning.deprecated_in((2, 4, 0)))
3120
def unregister_format(klass, format):
3121
format_registry.remove(format)
3124
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3125
"bzrlib.workingtree_4", "WorkingTreeFormat4")
3126
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3127
"bzrlib.workingtree_4", "WorkingTreeFormat5")
3128
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3129
"bzrlib.workingtree_4", "WorkingTreeFormat6")
3130
format_registry.register_lazy("Bazaar-NG Working Tree format 3",
3131
"bzrlib.workingtree_3", "WorkingTreeFormat3")
3132
format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")