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).
32
from __future__ import absolute_import
34
from cStringIO import StringIO
38
from bzrlib.lazy_import import lazy_import
39
lazy_import(globals(), """
40
from bisect import bisect_left
51
conflicts as _mod_conflicts,
54
filters as _mod_filters,
61
revision as _mod_revision,
73
# Explicitly import bzrlib.bzrdir so that the BzrProber
74
# is guaranteed to be registered.
77
from bzrlib import symbol_versioning
78
from bzrlib.decorators import needs_read_lock, needs_write_lock
79
from bzrlib.i18n import gettext
80
from bzrlib.lock import LogicalLockResult
81
import bzrlib.mutabletree
82
from bzrlib.mutabletree import needs_tree_write_lock
83
from bzrlib import osutils
84
from bzrlib.osutils import (
94
from bzrlib.trace import mutter, note
95
from bzrlib.revision import CURRENT_REVISION
96
from bzrlib.symbol_versioning import (
102
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
103
# TODO: Modifying the conflict objects or their type is currently nearly
104
# impossible as there is no clear relationship between the working tree format
105
# and the conflict list file format.
106
CONFLICT_HEADER_1 = "BZR conflict list format 1"
108
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
111
class TreeEntry(object):
112
"""An entry that implements the minimum interface used by commands.
114
This needs further inspection, it may be better to have
115
InventoryEntries without ids - though that seems wrong. For now,
116
this is a parallel hierarchy to InventoryEntry, and needs to become
117
one of several things: decorates to that hierarchy, children of, or
119
Another note is that these objects are currently only used when there is
120
no InventoryEntry available - i.e. for unversioned objects.
121
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
124
def __eq__(self, other):
125
# yes, this us ugly, TODO: best practice __eq__ style.
126
return (isinstance(other, TreeEntry)
127
and other.__class__ == self.__class__)
129
def kind_character(self):
133
class TreeDirectory(TreeEntry):
134
"""See TreeEntry. This is a directory in a working tree."""
136
def __eq__(self, other):
137
return (isinstance(other, TreeDirectory)
138
and other.__class__ == self.__class__)
140
def kind_character(self):
144
class TreeFile(TreeEntry):
145
"""See TreeEntry. This is a regular file in a working tree."""
147
def __eq__(self, other):
148
return (isinstance(other, TreeFile)
149
and other.__class__ == self.__class__)
151
def kind_character(self):
155
class TreeLink(TreeEntry):
156
"""See TreeEntry. This is a symlink in a working tree."""
158
def __eq__(self, other):
159
return (isinstance(other, TreeLink)
160
and other.__class__ == self.__class__)
162
def kind_character(self):
166
class WorkingTree(bzrlib.mutabletree.MutableTree,
167
controldir.ControlComponent):
168
"""Working copy tree.
170
:ivar basedir: The root of the tree on disk. This is a unicode path object
171
(as opposed to a URL).
174
# override this to set the strategy for storing views
175
def _make_views(self):
176
return views.DisabledViews(self)
178
def __init__(self, basedir='.',
179
branch=DEPRECATED_PARAMETER,
184
"""Construct a WorkingTree instance. This is not a public API.
186
:param branch: A branch to override probing for the branch.
188
self._format = _format
189
self.bzrdir = _bzrdir
191
raise errors.BzrError("Please use bzrdir.open_workingtree or "
192
"WorkingTree.open() to obtain a WorkingTree.")
193
basedir = safe_unicode(basedir)
194
mutter("opening working tree %r", basedir)
195
if deprecated_passed(branch):
196
self._branch = branch
198
self._branch = self.bzrdir.open_branch()
199
self.basedir = realpath(basedir)
200
self._transport = _transport
201
self._rules_searcher = None
202
self.views = self._make_views()
205
def user_transport(self):
206
return self.bzrdir.user_transport
209
def control_transport(self):
210
return self._transport
212
def is_control_filename(self, filename):
213
"""True if filename is the name of a control file in this tree.
215
:param filename: A filename within the tree. This is a relative path
216
from the root of this tree.
218
This is true IF and ONLY IF the filename is part of the meta data
219
that bzr controls in this tree. I.E. a random .bzr directory placed
220
on disk will not be a control file for this tree.
222
return self.bzrdir.is_control_filename(filename)
225
fget=lambda self: self._branch,
226
doc="""The branch this WorkingTree is connected to.
228
This cannot be set - it is reflective of the actual disk structure
229
the working tree has been constructed from.
232
def has_versioned_directories(self):
233
"""See `Tree.has_versioned_directories`."""
234
return self._format.supports_versioned_directories
236
def break_lock(self):
237
"""Break a lock if one is present from another instance.
239
Uses the ui factory to ask for confirmation if the lock may be from
242
This will probe the repository for its lock as well.
244
raise NotImplementedError(self.break_lock)
246
def requires_rich_root(self):
247
return self._format.requires_rich_root
249
def supports_tree_reference(self):
252
def supports_content_filtering(self):
253
return self._format.supports_content_filtering()
255
def supports_views(self):
256
return self.views.supports_views()
259
def open(path=None, _unsupported=False):
260
"""Open an existing working tree at path.
264
path = osutils.getcwd()
265
control = controldir.ControlDir.open(path, _unsupported)
266
return control.open_workingtree(_unsupported)
269
def open_containing(path=None):
270
"""Open an existing working tree which has its root about path.
272
This probes for a working tree at path and searches upwards from there.
274
Basically we keep looking up until we find the control directory or
275
run into /. If there isn't one, raises NotBranchError.
276
TODO: give this a new exception.
277
If there is one, it is returned, along with the unused portion of path.
279
:return: The WorkingTree that contains 'path', and the rest of path
282
path = osutils.getcwd()
283
control, relpath = controldir.ControlDir.open_containing(path)
284
return control.open_workingtree(), relpath
287
def open_containing_paths(file_list, default_directory=None,
288
canonicalize=True, apply_view=True):
289
"""Open the WorkingTree that contains a set of paths.
291
Fail if the paths given are not all in a single tree.
293
This is used for the many command-line interfaces that take a list of
294
any number of files and that require they all be in the same tree.
296
if default_directory is None:
297
default_directory = u'.'
298
# recommended replacement for builtins.internal_tree_files
299
if file_list is None or len(file_list) == 0:
300
tree = WorkingTree.open_containing(default_directory)[0]
301
# XXX: doesn't really belong here, and seems to have the strange
302
# side effect of making it return a bunch of files, not the whole
303
# tree -- mbp 20100716
304
if tree.supports_views() and apply_view:
305
view_files = tree.views.lookup_view()
307
file_list = view_files
308
view_str = views.view_display_str(view_files)
309
note(gettext("Ignoring files outside view. View is %s") % view_str)
310
return tree, file_list
311
if default_directory == u'.':
314
seed = default_directory
315
file_list = [osutils.pathjoin(default_directory, f)
317
tree = WorkingTree.open_containing(seed)[0]
318
return tree, tree.safe_relpath_files(file_list, canonicalize,
319
apply_view=apply_view)
321
def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
322
"""Convert file_list into a list of relpaths in tree.
324
:param self: A tree to operate on.
325
:param file_list: A list of user provided paths or None.
326
:param apply_view: if True and a view is set, apply it or check that
327
specified files are within it
328
:return: A list of relative paths.
329
:raises errors.PathNotChild: When a provided path is in a different self
332
if file_list is None:
334
if self.supports_views() and apply_view:
335
view_files = self.views.lookup_view()
339
# self.relpath exists as a "thunk" to osutils, but canonical_relpath
340
# doesn't - fix that up here before we enter the loop.
342
fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
345
for filename in file_list:
346
relpath = fixer(osutils.dereference_path(filename))
347
if view_files and not osutils.is_inside_any(view_files, relpath):
348
raise errors.FileOutsideView(filename, view_files)
349
new_list.append(relpath)
353
def open_downlevel(path=None):
354
"""Open an unsupported working tree.
356
Only intended for advanced situations like upgrading part of a bzrdir.
358
return WorkingTree.open(path, _unsupported=True)
361
def find_trees(location):
362
def list_current(transport):
363
return [d for d in transport.list_dir('') if d != '.bzr']
364
def evaluate(bzrdir):
366
tree = bzrdir.open_workingtree()
367
except errors.NoWorkingTree:
371
t = transport.get_transport(location)
372
iterator = controldir.ControlDir.find_bzrdirs(t, evaluate=evaluate,
373
list_current=list_current)
374
return [tr for tr in iterator if tr is not None]
376
def all_file_ids(self):
377
"""See Tree.iter_all_file_ids"""
378
raise NotImplementedError(self.all_file_ids)
381
return "<%s of %s>" % (self.__class__.__name__,
382
getattr(self, 'basedir', None))
384
def abspath(self, filename):
385
return pathjoin(self.basedir, filename)
387
def basis_tree(self):
388
"""Return RevisionTree for the current last revision.
390
If the left most parent is a ghost then the returned tree will be an
391
empty tree - one obtained by calling
392
repository.revision_tree(NULL_REVISION).
395
revision_id = self.get_parent_ids()[0]
397
# no parents, return an empty revision tree.
398
# in the future this should return the tree for
399
# 'empty:' - the implicit root empty tree.
400
return self.branch.repository.revision_tree(
401
_mod_revision.NULL_REVISION)
403
return self.revision_tree(revision_id)
404
except errors.NoSuchRevision:
406
# No cached copy available, retrieve from the repository.
407
# FIXME? RBC 20060403 should we cache the inventory locally
410
return self.branch.repository.revision_tree(revision_id)
411
except (errors.RevisionNotPresent, errors.NoSuchRevision):
412
# the basis tree *may* be a ghost or a low level error may have
413
# occurred. If the revision is present, its a problem, if its not
415
if self.branch.repository.has_revision(revision_id):
417
# the basis tree is a ghost so return an empty tree.
418
return self.branch.repository.revision_tree(
419
_mod_revision.NULL_REVISION)
422
self._flush_ignore_list_cache()
424
def relpath(self, path):
425
"""Return the local path portion from a given path.
427
The path may be absolute or relative. If its a relative path it is
428
interpreted relative to the python current working directory.
430
return osutils.relpath(self.basedir, path)
432
def has_filename(self, filename):
433
return osutils.lexists(self.abspath(filename))
435
def get_file(self, file_id, path=None, filtered=True):
436
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
438
def get_file_with_stat(self, file_id, path=None, filtered=True,
439
_fstat=osutils.fstat):
440
"""See Tree.get_file_with_stat."""
442
path = self.id2path(file_id)
443
file_obj = self.get_file_byname(path, filtered=False)
444
stat_value = _fstat(file_obj.fileno())
445
if filtered and self.supports_content_filtering():
446
filters = self._content_filter_stack(path)
447
file_obj = _mod_filters.filtered_input_file(file_obj, filters)
448
return (file_obj, stat_value)
450
def get_file_text(self, file_id, path=None, filtered=True):
451
my_file = self.get_file(file_id, path=path, filtered=filtered)
453
return my_file.read()
457
def get_file_byname(self, filename, filtered=True):
458
path = self.abspath(filename)
460
if filtered and self.supports_content_filtering():
461
filters = self._content_filter_stack(filename)
462
return _mod_filters.filtered_input_file(f, filters)
466
def get_file_lines(self, file_id, path=None, filtered=True):
467
"""See Tree.get_file_lines()"""
468
file = self.get_file(file_id, path, filtered=filtered)
470
return file.readlines()
474
def get_parent_ids(self):
475
"""See Tree.get_parent_ids.
477
This implementation reads the pending merges list and last_revision
478
value and uses that to decide what the parents list should be.
480
last_rev = _mod_revision.ensure_null(self._last_revision())
481
if _mod_revision.NULL_REVISION == last_rev:
486
merges_bytes = self._transport.get_bytes('pending-merges')
487
except errors.NoSuchFile:
490
for l in osutils.split_lines(merges_bytes):
491
revision_id = l.rstrip('\n')
492
parents.append(revision_id)
495
def get_root_id(self):
496
"""Return the id of this trees root"""
497
raise NotImplementedError(self.get_root_id)
500
def clone(self, to_controldir, revision_id=None):
501
"""Duplicate this working tree into to_bzr, including all state.
503
Specifically modified files are kept as modified, but
504
ignored and unknown files are discarded.
506
If you want to make a new line of development, see ControlDir.sprout()
509
If not None, the cloned tree will have its last revision set to
510
revision, and difference between the source trees last revision
511
and this one merged in.
513
# assumes the target bzr dir format is compatible.
514
result = to_controldir.create_workingtree()
515
self.copy_content_into(result, revision_id)
519
def copy_content_into(self, tree, revision_id=None):
520
"""Copy the current content and user files of this tree into tree."""
521
tree.set_root_id(self.get_root_id())
522
if revision_id is None:
523
merge.transform_tree(tree, self)
525
# TODO now merge from tree.last_revision to revision (to preserve
526
# user local changes)
527
merge.transform_tree(tree, self)
528
if revision_id == _mod_revision.NULL_REVISION:
531
new_parents = [revision_id]
532
tree.set_parent_ids(new_parents)
534
def id2abspath(self, file_id):
535
return self.abspath(self.id2path(file_id))
537
def _check_for_tree_references(self, iterator):
538
"""See if directories have become tree-references."""
539
blocked_parent_ids = set()
540
for path, ie in iterator:
541
if ie.parent_id in blocked_parent_ids:
542
# This entry was pruned because one of its parents became a
543
# TreeReference. If this is a directory, mark it as blocked.
544
if ie.kind == 'directory':
545
blocked_parent_ids.add(ie.file_id)
547
if ie.kind == 'directory' and self._directory_is_tree_reference(path):
548
# This InventoryDirectory needs to be a TreeReference
549
ie = inventory.TreeReference(ie.file_id, ie.name, ie.parent_id)
550
blocked_parent_ids.add(ie.file_id)
553
def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
554
"""See Tree.iter_entries_by_dir()"""
555
# The only trick here is that if we supports_tree_reference then we
556
# need to detect if a directory becomes a tree-reference.
557
iterator = super(WorkingTree, self).iter_entries_by_dir(
558
specific_file_ids=specific_file_ids,
559
yield_parents=yield_parents)
560
if not self.supports_tree_reference():
563
return self._check_for_tree_references(iterator)
565
def get_file_size(self, file_id):
566
"""See Tree.get_file_size"""
567
# XXX: this returns the on-disk size; it should probably return the
570
return os.path.getsize(self.id2abspath(file_id))
572
if e.errno != errno.ENOENT:
577
@needs_tree_write_lock
578
def _gather_kinds(self, files, kinds):
579
"""See MutableTree._gather_kinds."""
580
for pos, f in enumerate(files):
581
if kinds[pos] is None:
582
fullpath = normpath(self.abspath(f))
584
kinds[pos] = file_kind(fullpath)
586
if e.errno == errno.ENOENT:
587
raise errors.NoSuchFile(fullpath)
590
def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
591
"""Add revision_id as a parent.
593
This is equivalent to retrieving the current list of parent ids
594
and setting the list to its value plus revision_id.
596
:param revision_id: The revision id to add to the parent list. It may
597
be a ghost revision as long as its not the first parent to be
598
added, or the allow_leftmost_as_ghost parameter is set True.
599
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
601
parents = self.get_parent_ids() + [revision_id]
602
self.set_parent_ids(parents, allow_leftmost_as_ghost=len(parents) > 1
603
or allow_leftmost_as_ghost)
605
@needs_tree_write_lock
606
def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
607
"""Add revision_id, tree tuple as a parent.
609
This is equivalent to retrieving the current list of parent trees
610
and setting the list to its value plus parent_tuple. See also
611
add_parent_tree_id - if you only have a parent id available it will be
612
simpler to use that api. If you have the parent already available, using
613
this api is preferred.
615
:param parent_tuple: The (revision id, tree) to add to the parent list.
616
If the revision_id is a ghost, pass None for the tree.
617
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
619
parent_ids = self.get_parent_ids() + [parent_tuple[0]]
620
if len(parent_ids) > 1:
621
# the leftmost may have already been a ghost, preserve that if it
623
allow_leftmost_as_ghost = True
624
self.set_parent_ids(parent_ids,
625
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
627
@needs_tree_write_lock
628
def add_pending_merge(self, *revision_ids):
629
# TODO: Perhaps should check at this point that the
630
# history of the revision is actually present?
631
parents = self.get_parent_ids()
633
for rev_id in revision_ids:
634
if rev_id in parents:
636
parents.append(rev_id)
639
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
641
def path_content_summary(self, path, _lstat=os.lstat,
642
_mapper=osutils.file_kind_from_stat_mode):
643
"""See Tree.path_content_summary."""
644
abspath = self.abspath(path)
646
stat_result = _lstat(abspath)
648
if getattr(e, 'errno', None) == errno.ENOENT:
650
return ('missing', None, None, None)
651
# propagate other errors
653
kind = _mapper(stat_result.st_mode)
655
return self._file_content_summary(path, stat_result)
656
elif kind == 'directory':
657
# perhaps it looks like a plain directory, but it's really a
659
if self._directory_is_tree_reference(path):
660
kind = 'tree-reference'
661
return kind, None, None, None
662
elif kind == 'symlink':
663
target = osutils.readlink(abspath)
664
return ('symlink', None, None, target)
666
return (kind, None, None, None)
668
def _file_content_summary(self, path, stat_result):
669
size = stat_result.st_size
670
executable = self._is_executable_from_path_and_stat(path, stat_result)
671
# try for a stat cache lookup
672
return ('file', size, executable, self._sha_from_stat(
675
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
676
"""Common ghost checking functionality from set_parent_*.
678
This checks that the left hand-parent exists if there are any
681
if len(revision_ids) > 0:
682
leftmost_id = revision_ids[0]
683
if (not allow_leftmost_as_ghost and not
684
self.branch.repository.has_revision(leftmost_id)):
685
raise errors.GhostRevisionUnusableHere(leftmost_id)
687
def _set_merges_from_parent_ids(self, parent_ids):
688
merges = parent_ids[1:]
689
self._transport.put_bytes('pending-merges', '\n'.join(merges),
690
mode=self.bzrdir._get_file_mode())
692
def _filter_parent_ids_by_ancestry(self, revision_ids):
693
"""Check that all merged revisions are proper 'heads'.
695
This will always return the first revision_id, and any merged revisions
698
if len(revision_ids) == 0:
700
graph = self.branch.repository.get_graph()
701
heads = graph.heads(revision_ids)
702
new_revision_ids = revision_ids[:1]
703
for revision_id in revision_ids[1:]:
704
if revision_id in heads and revision_id not in new_revision_ids:
705
new_revision_ids.append(revision_id)
706
if new_revision_ids != revision_ids:
707
mutter('requested to set revision_ids = %s,'
708
' but filtered to %s', revision_ids, new_revision_ids)
709
return new_revision_ids
711
@needs_tree_write_lock
712
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
713
"""Set the parent ids to revision_ids.
715
See also set_parent_trees. This api will try to retrieve the tree data
716
for each element of revision_ids from the trees repository. If you have
717
tree data already available, it is more efficient to use
718
set_parent_trees rather than set_parent_ids. set_parent_ids is however
719
an easier API to use.
721
:param revision_ids: The revision_ids to set as the parent ids of this
722
working tree. Any of these may be ghosts.
724
self._check_parents_for_ghosts(revision_ids,
725
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
726
for revision_id in revision_ids:
727
_mod_revision.check_not_reserved_id(revision_id)
729
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
731
if len(revision_ids) > 0:
732
self.set_last_revision(revision_ids[0])
734
self.set_last_revision(_mod_revision.NULL_REVISION)
736
self._set_merges_from_parent_ids(revision_ids)
738
@needs_tree_write_lock
739
def set_pending_merges(self, rev_list):
740
parents = self.get_parent_ids()
741
leftmost = parents[:1]
742
new_parents = leftmost + rev_list
743
self.set_parent_ids(new_parents)
745
@needs_tree_write_lock
746
def set_merge_modified(self, modified_hashes):
747
"""Set the merge modified hashes."""
748
raise NotImplementedError(self.set_merge_modified)
750
def _sha_from_stat(self, path, stat_result):
751
"""Get a sha digest from the tree's stat cache.
753
The default implementation assumes no stat cache is present.
755
:param path: The path.
756
:param stat_result: The stat result being looked up.
760
@needs_write_lock # because merge pulls data into the branch.
761
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
762
merge_type=None, force=False):
763
"""Merge from a branch into this working tree.
765
:param branch: The branch to merge from.
766
:param to_revision: If non-None, the merge will merge to to_revision,
767
but not beyond it. to_revision does not need to be in the history
768
of the branch when it is supplied. If None, to_revision defaults to
769
branch.last_revision().
771
from bzrlib.merge import Merger, Merge3Merger
772
merger = Merger(self.branch, this_tree=self)
773
# check that there are no local alterations
774
if not force and self.has_changes():
775
raise errors.UncommittedChanges(self)
776
if to_revision is None:
777
to_revision = _mod_revision.ensure_null(branch.last_revision())
778
merger.other_rev_id = to_revision
779
if _mod_revision.is_null(merger.other_rev_id):
780
raise errors.NoCommits(branch)
781
self.branch.fetch(branch, last_revision=merger.other_rev_id)
782
merger.other_basis = merger.other_rev_id
783
merger.other_tree = self.branch.repository.revision_tree(
785
merger.other_branch = branch
786
if from_revision is None:
789
merger.set_base_revision(from_revision, branch)
790
if merger.base_rev_id == merger.other_rev_id:
791
raise errors.PointlessMerge
792
merger.backup_files = False
793
if merge_type is None:
794
merger.merge_type = Merge3Merger
796
merger.merge_type = merge_type
797
merger.set_interesting_files(None)
798
merger.show_base = False
799
merger.reprocess = False
800
conflicts = merger.do_merge()
804
def merge_modified(self):
805
"""Return a dictionary of files modified by a merge.
807
The list is initialized by WorkingTree.set_merge_modified, which is
808
typically called after we make some automatic updates to the tree
811
This returns a map of file_id->sha1, containing only files which are
812
still in the working inventory and have that text hash.
814
raise NotImplementedError(self.merge_modified)
817
def mkdir(self, path, file_id=None):
818
"""See MutableTree.mkdir()."""
820
file_id = generate_ids.gen_file_id(os.path.basename(path))
821
os.mkdir(self.abspath(path))
822
self.add(path, file_id, 'directory')
825
def get_symlink_target(self, file_id, path=None):
827
abspath = self.abspath(path)
829
abspath = self.id2abspath(file_id)
830
target = osutils.readlink(abspath)
833
def subsume(self, other_tree):
834
raise NotImplementedError(self.subsume)
836
def _setup_directory_is_tree_reference(self):
837
if self._branch.repository._format.supports_tree_reference:
838
self._directory_is_tree_reference = \
839
self._directory_may_be_tree_reference
841
self._directory_is_tree_reference = \
842
self._directory_is_never_tree_reference
844
def _directory_is_never_tree_reference(self, relpath):
847
def _directory_may_be_tree_reference(self, relpath):
848
# as a special case, if a directory contains control files then
849
# it's a tree reference, except that the root of the tree is not
850
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
851
# TODO: We could ask all the control formats whether they
852
# recognize this directory, but at the moment there's no cheap api
853
# to do that. Since we probably can only nest bzr checkouts and
854
# they always use this name it's ok for now. -- mbp 20060306
856
# FIXME: There is an unhandled case here of a subdirectory
857
# containing .bzr but not a branch; that will probably blow up
858
# when you try to commit it. It might happen if there is a
859
# checkout in a subdirectory. This can be avoided by not adding
862
def extract(self, file_id, format=None):
863
"""Extract a subtree from this tree.
865
A new branch will be created, relative to the path for this tree.
867
raise NotImplementedError(self.extract)
870
"""Write the in memory meta data to disk."""
871
raise NotImplementedError(self.flush)
873
def _kind(self, relpath):
874
return osutils.file_kind(self.abspath(relpath))
876
def list_files(self, include_root=False, from_dir=None, recursive=True):
877
"""List all files as (path, class, kind, id, entry).
879
Lists, but does not descend into unversioned directories.
880
This does not include files that have been deleted in this
881
tree. Skips the control directory.
883
:param include_root: if True, return an entry for the root
884
:param from_dir: start from this directory or None for the root
885
:param recursive: whether to recurse into subdirectories or not
887
raise NotImplementedError(self.list_files)
889
def move(self, from_paths, to_dir=None, after=False):
892
to_dir must be known to the working tree.
894
If to_dir exists and is a directory, the files are moved into
895
it, keeping their old names.
897
Note that to_dir is only the last component of the new name;
898
this doesn't change the directory.
900
For each entry in from_paths the move mode will be determined
903
The first mode moves the file in the filesystem and updates the
904
working tree metadata. The second mode only updates the working tree
905
metadata without touching the file on the filesystem.
907
move uses the second mode if 'after == True' and the target is not
908
versioned but present in the working tree.
910
move uses the second mode if 'after == False' and the source is
911
versioned but no longer in the working tree, and the target is not
912
versioned but present in the working tree.
914
move uses the first mode if 'after == False' and the source is
915
versioned and present in the working tree, and the target is not
916
versioned and not present in the working tree.
918
Everything else results in an error.
920
This returns a list of (from_path, to_path) pairs for each
923
raise NotImplementedError(self.move)
925
@needs_tree_write_lock
926
def rename_one(self, from_rel, to_rel, after=False):
929
This can change the directory or the filename or both.
931
rename_one has several 'modes' to work. First, it can rename a physical
932
file and change the file_id. That is the normal mode. Second, it can
933
only change the file_id without touching any physical file.
935
rename_one uses the second mode if 'after == True' and 'to_rel' is
936
either not versioned or newly added, and present in the working tree.
938
rename_one uses the second mode if 'after == False' and 'from_rel' is
939
versioned but no longer in the working tree, and 'to_rel' is not
940
versioned but present in the working tree.
942
rename_one uses the first mode if 'after == False' and 'from_rel' is
943
versioned and present in the working tree, and 'to_rel' is not
944
versioned and not present in the working tree.
946
Everything else results in an error.
948
raise NotImplementedError(self.rename_one)
952
"""Return all unknown files.
954
These are files in the working directory that are not versioned or
955
control files or ignored.
957
# force the extras method to be fully executed before returning, to
958
# prevent race conditions with the lock
960
[subp for subp in self.extras() if not self.is_ignored(subp)])
962
def unversion(self, file_ids):
963
"""Remove the file ids in file_ids from the current versioned set.
965
When a file_id is unversioned, all of its children are automatically
968
:param file_ids: The file ids to stop versioning.
969
:raises: NoSuchId if any fileid is not currently versioned.
971
raise NotImplementedError(self.unversion)
974
def pull(self, source, overwrite=False, stop_revision=None,
975
change_reporter=None, possible_transports=None, local=False,
979
old_revision_info = self.branch.last_revision_info()
980
basis_tree = self.basis_tree()
981
count = self.branch.pull(source, overwrite, stop_revision,
982
possible_transports=possible_transports,
984
new_revision_info = self.branch.last_revision_info()
985
if new_revision_info != old_revision_info:
986
repository = self.branch.repository
987
if repository._format.fast_deltas:
988
parent_ids = self.get_parent_ids()
990
basis_id = parent_ids[0]
991
basis_tree = repository.revision_tree(basis_id)
992
basis_tree.lock_read()
994
new_basis_tree = self.branch.basis_tree()
1001
change_reporter=change_reporter,
1002
show_base=show_base)
1003
basis_root_id = basis_tree.get_root_id()
1004
new_root_id = new_basis_tree.get_root_id()
1005
if new_root_id is not None and basis_root_id != new_root_id:
1006
self.set_root_id(new_root_id)
1009
# TODO - dedup parents list with things merged by pull ?
1010
# reuse the revisiontree we merged against to set the new
1013
if self.branch.last_revision() != _mod_revision.NULL_REVISION:
1014
parent_trees.append(
1015
(self.branch.last_revision(), new_basis_tree))
1016
# we have to pull the merge trees out again, because
1017
# merge_inner has set the ids. - this corner is not yet
1018
# layered well enough to prevent double handling.
1019
# XXX TODO: Fix the double handling: telling the tree about
1020
# the already known parent data is wasteful.
1021
merges = self.get_parent_ids()[1:]
1022
parent_trees.extend([
1023
(parent, repository.revision_tree(parent)) for
1025
self.set_parent_trees(parent_trees)
1031
def put_file_bytes_non_atomic(self, file_id, bytes):
1032
"""See MutableTree.put_file_bytes_non_atomic."""
1033
stream = file(self.id2abspath(file_id), 'wb')
1040
"""Yield all unversioned files in this WorkingTree.
1042
If there are any unversioned directories then only the directory is
1043
returned, not all its children. But if there are unversioned files
1044
under a versioned subdirectory, they are returned.
1046
Currently returned depth-first, sorted by name within directories.
1047
This is the same order used by 'osutils.walkdirs'.
1049
raise NotImplementedError(self.extras)
1051
def ignored_files(self):
1052
"""Yield list of PATH, IGNORE_PATTERN"""
1053
for subp in self.extras():
1054
pat = self.is_ignored(subp)
1058
def get_ignore_list(self):
1059
"""Return list of ignore patterns.
1061
Cached in the Tree object after the first call.
1063
ignoreset = getattr(self, '_ignoreset', None)
1064
if ignoreset is not None:
1067
ignore_globs = set()
1068
ignore_globs.update(ignores.get_runtime_ignores())
1069
ignore_globs.update(ignores.get_user_ignores())
1070
if self.has_filename(bzrlib.IGNORE_FILENAME):
1071
f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
1073
ignore_globs.update(ignores.parse_ignore_file(f))
1076
self._ignoreset = ignore_globs
1079
def _flush_ignore_list_cache(self):
1080
"""Resets the cached ignore list to force a cache rebuild."""
1081
self._ignoreset = None
1082
self._ignoreglobster = None
1084
def is_ignored(self, filename):
1085
r"""Check whether the filename matches an ignore pattern.
1087
Patterns containing '/' or '\' need to match the whole path;
1088
others match against only the last component. Patterns starting
1089
with '!' are ignore exceptions. Exceptions take precedence
1090
over regular patterns and cause the filename to not be ignored.
1092
If the file is ignored, returns the pattern which caused it to
1093
be ignored, otherwise None. So this can simply be used as a
1094
boolean if desired."""
1095
if getattr(self, '_ignoreglobster', None) is None:
1096
self._ignoreglobster = globbing.ExceptionGlobster(self.get_ignore_list())
1097
return self._ignoreglobster.match(filename)
1099
def kind(self, file_id):
1100
return file_kind(self.id2abspath(file_id))
1102
def stored_kind(self, file_id):
1103
"""See Tree.stored_kind"""
1104
raise NotImplementedError(self.stored_kind)
1106
def _comparison_data(self, entry, path):
1107
abspath = self.abspath(path)
1109
stat_value = os.lstat(abspath)
1111
if getattr(e, 'errno', None) == errno.ENOENT:
1118
mode = stat_value.st_mode
1119
kind = osutils.file_kind_from_stat_mode(mode)
1120
if not supports_executable():
1121
executable = entry is not None and entry.executable
1123
executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1124
return kind, executable, stat_value
1126
def _file_size(self, entry, stat_value):
1127
return stat_value.st_size
1129
def last_revision(self):
1130
"""Return the last revision of the branch for this tree.
1132
This format tree does not support a separate marker for last-revision
1133
compared to the branch.
1135
See MutableTree.last_revision
1137
return self._last_revision()
1140
def _last_revision(self):
1141
"""helper for get_parent_ids."""
1142
return _mod_revision.ensure_null(self.branch.last_revision())
1144
def is_locked(self):
1145
"""Check if this tree is locked."""
1146
raise NotImplementedError(self.is_locked)
1148
def lock_read(self):
1149
"""Lock the tree for reading.
1151
This also locks the branch, and can be unlocked via self.unlock().
1153
:return: A bzrlib.lock.LogicalLockResult.
1155
raise NotImplementedError(self.lock_read)
1157
def lock_tree_write(self):
1158
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1160
:return: A bzrlib.lock.LogicalLockResult.
1162
raise NotImplementedError(self.lock_tree_write)
1164
def lock_write(self):
1165
"""See MutableTree.lock_write, and WorkingTree.unlock.
1167
:return: A bzrlib.lock.LogicalLockResult.
1169
raise NotImplementedError(self.lock_write)
1171
def get_physical_lock_status(self):
1172
raise NotImplementedError(self.get_physical_lock_status)
1174
def set_last_revision(self, new_revision):
1175
"""Change the last revision in the working tree."""
1176
raise NotImplementedError(self.set_last_revision)
1178
def _change_last_revision(self, new_revision):
1179
"""Template method part of set_last_revision to perform the change.
1181
This is used to allow WorkingTree3 instances to not affect branch
1182
when their last revision is set.
1184
if _mod_revision.is_null(new_revision):
1185
self.branch.set_last_revision_info(0, new_revision)
1187
_mod_revision.check_not_reserved_id(new_revision)
1189
self.branch.generate_revision_history(new_revision)
1190
except errors.NoSuchRevision:
1191
# not present in the repo - dont try to set it deeper than the tip
1192
self.branch._set_revision_history([new_revision])
1195
@needs_tree_write_lock
1196
def remove(self, files, verbose=False, to_file=None, keep_files=True,
1198
"""Remove nominated files from the working tree metadata.
1200
:files: File paths relative to the basedir.
1201
:keep_files: If true, the files will also be kept.
1202
:force: Delete files and directories, even if they are changed and
1203
even if the directories are not empty.
1205
if isinstance(files, basestring):
1210
all_files = set() # specified and nested files
1211
unknown_nested_files=set()
1213
to_file = sys.stdout
1215
files_to_backup = []
1217
def recurse_directory_to_add_files(directory):
1218
# Recurse directory and add all files
1219
# so we can check if they have changed.
1220
for parent_info, file_infos in self.walkdirs(directory):
1221
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1222
# Is it versioned or ignored?
1223
if self.path2id(relpath):
1224
# Add nested content for deletion.
1225
all_files.add(relpath)
1227
# Files which are not versioned
1228
# should be treated as unknown.
1229
files_to_backup.append(relpath)
1231
for filename in files:
1232
# Get file name into canonical form.
1233
abspath = self.abspath(filename)
1234
filename = self.relpath(abspath)
1235
if len(filename) > 0:
1236
all_files.add(filename)
1237
recurse_directory_to_add_files(filename)
1239
files = list(all_files)
1242
return # nothing to do
1244
# Sort needed to first handle directory content before the directory
1245
files.sort(reverse=True)
1247
# Bail out if we are going to delete files we shouldn't
1248
if not keep_files and not force:
1249
for (file_id, path, content_change, versioned, parent_id, name,
1250
kind, executable) in self.iter_changes(self.basis_tree(),
1251
include_unchanged=True, require_versioned=False,
1252
want_unversioned=True, specific_files=files):
1253
if versioned[0] == False:
1254
# The record is unknown or newly added
1255
files_to_backup.append(path[1])
1256
elif (content_change and (kind[1] is not None) and
1257
osutils.is_inside_any(files, path[1])):
1258
# Versioned and changed, but not deleted, and still
1259
# in one of the dirs to be deleted.
1260
files_to_backup.append(path[1])
1262
def backup(file_to_backup):
1263
backup_name = self.bzrdir._available_backup_name(file_to_backup)
1264
osutils.rename(abs_path, self.abspath(backup_name))
1265
return "removed %s (but kept a copy: %s)" % (file_to_backup,
1268
# Build inv_delta and delete files where applicable,
1269
# do this before any modifications to meta data.
1271
fid = self.path2id(f)
1274
message = "%s is not versioned." % (f,)
1277
# having removed it, it must be either ignored or unknown
1278
if self.is_ignored(f):
1282
# XXX: Really should be a more abstract reporter interface
1283
kind_ch = osutils.kind_marker(self.kind(fid))
1284
to_file.write(new_status + ' ' + f + kind_ch + '\n')
1286
inv_delta.append((f, None, fid, None))
1287
message = "removed %s" % (f,)
1290
abs_path = self.abspath(f)
1291
if osutils.lexists(abs_path):
1292
if (osutils.isdir(abs_path) and
1293
len(os.listdir(abs_path)) > 0):
1295
osutils.rmtree(abs_path)
1296
message = "deleted %s" % (f,)
1300
if f in files_to_backup:
1303
osutils.delete_any(abs_path)
1304
message = "deleted %s" % (f,)
1305
elif message is not None:
1306
# Only care if we haven't done anything yet.
1307
message = "%s does not exist." % (f,)
1309
# Print only one message (if any) per file.
1310
if message is not None:
1312
self.apply_inventory_delta(inv_delta)
1314
@needs_tree_write_lock
1315
def revert(self, filenames=None, old_tree=None, backups=True,
1316
pb=None, report_changes=False):
1317
from bzrlib.conflicts import resolve
1318
if old_tree is None:
1319
basis_tree = self.basis_tree()
1320
basis_tree.lock_read()
1321
old_tree = basis_tree
1325
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1327
if filenames is None and len(self.get_parent_ids()) > 1:
1329
last_revision = self.last_revision()
1330
if last_revision != _mod_revision.NULL_REVISION:
1331
if basis_tree is None:
1332
basis_tree = self.basis_tree()
1333
basis_tree.lock_read()
1334
parent_trees.append((last_revision, basis_tree))
1335
self.set_parent_trees(parent_trees)
1338
resolve(self, filenames, ignore_misses=True, recursive=True)
1340
if basis_tree is not None:
1344
def revision_tree(self, revision_id):
1345
"""See Tree.revision_tree.
1347
WorkingTree can supply revision_trees for the basis revision only
1348
because there is only one cached inventory in the bzr directory.
1350
raise NotImplementedError(self.revision_tree)
1352
@needs_tree_write_lock
1353
def set_root_id(self, file_id):
1354
"""Set the root id for this tree."""
1358
'WorkingTree.set_root_id with fileid=None')
1359
file_id = osutils.safe_file_id(file_id)
1360
self._set_root_id(file_id)
1362
def _set_root_id(self, file_id):
1363
"""Set the root id for this tree, in a format specific manner.
1365
:param file_id: The file id to assign to the root. It must not be
1366
present in the current inventory or an error will occur. It must
1367
not be None, but rather a valid file id.
1369
raise NotImplementedError(self._set_root_id)
1372
"""See Branch.unlock.
1374
WorkingTree locking just uses the Branch locking facilities.
1375
This is current because all working trees have an embedded branch
1376
within them. IF in the future, we were to make branch data shareable
1377
between multiple working trees, i.e. via shared storage, then we
1378
would probably want to lock both the local tree, and the branch.
1380
raise NotImplementedError(self.unlock)
1384
def update(self, change_reporter=None, possible_transports=None,
1385
revision=None, old_tip=_marker, show_base=False):
1386
"""Update a working tree along its branch.
1388
This will update the branch if its bound too, which means we have
1389
multiple trees involved:
1391
- The new basis tree of the master.
1392
- The old basis tree of the branch.
1393
- The old basis tree of the working tree.
1394
- The current working tree state.
1396
Pathologically, all three may be different, and non-ancestors of each
1397
other. Conceptually we want to:
1399
- Preserve the wt.basis->wt.state changes
1400
- Transform the wt.basis to the new master basis.
1401
- Apply a merge of the old branch basis to get any 'local' changes from
1403
- Restore the wt.basis->wt.state changes.
1405
There isn't a single operation at the moment to do that, so we:
1407
- Merge current state -> basis tree of the master w.r.t. the old tree
1409
- Do a 'normal' merge of the old branch basis if it is relevant.
1411
:param revision: The target revision to update to. Must be in the
1413
:param old_tip: If branch.update() has already been run, the value it
1414
returned (old tip of the branch or None). _marker is used
1417
if self.branch.get_bound_location() is not None:
1419
update_branch = (old_tip is self._marker)
1421
self.lock_tree_write()
1422
update_branch = False
1425
old_tip = self.branch.update(possible_transports)
1427
if old_tip is self._marker:
1429
return self._update_tree(old_tip, change_reporter, revision, show_base)
1433
@needs_tree_write_lock
1434
def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
1436
"""Update a tree to the master branch.
1438
:param old_tip: if supplied, the previous tip revision the branch,
1439
before it was changed to the master branch's tip.
1441
# here if old_tip is not None, it is the old tip of the branch before
1442
# it was updated from the master branch. This should become a pending
1443
# merge in the working tree to preserve the user existing work. we
1444
# cant set that until we update the working trees last revision to be
1445
# one from the new branch, because it will just get absorbed by the
1446
# parent de-duplication logic.
1448
# We MUST save it even if an error occurs, because otherwise the users
1449
# local work is unreferenced and will appear to have been lost.
1453
last_rev = self.get_parent_ids()[0]
1455
last_rev = _mod_revision.NULL_REVISION
1456
if revision is None:
1457
revision = self.branch.last_revision()
1459
old_tip = old_tip or _mod_revision.NULL_REVISION
1461
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
1462
# the branch we are bound to was updated
1463
# merge those changes in first
1464
base_tree = self.basis_tree()
1465
other_tree = self.branch.repository.revision_tree(old_tip)
1466
nb_conflicts = merge.merge_inner(self.branch, other_tree,
1467
base_tree, this_tree=self,
1468
change_reporter=change_reporter,
1469
show_base=show_base)
1471
self.add_parent_tree((old_tip, other_tree))
1472
note(gettext('Rerun update after fixing the conflicts.'))
1475
if last_rev != _mod_revision.ensure_null(revision):
1476
# the working tree is up to date with the branch
1477
# we can merge the specified revision from master
1478
to_tree = self.branch.repository.revision_tree(revision)
1479
to_root_id = to_tree.get_root_id()
1481
basis = self.basis_tree()
1484
if (basis.get_root_id() is None or basis.get_root_id() != to_root_id):
1485
self.set_root_id(to_root_id)
1490
# determine the branch point
1491
graph = self.branch.repository.get_graph()
1492
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
1494
base_tree = self.branch.repository.revision_tree(base_rev_id)
1496
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
1498
change_reporter=change_reporter,
1499
show_base=show_base)
1500
self.set_last_revision(revision)
1501
# TODO - dedup parents list with things merged by pull ?
1502
# reuse the tree we've updated to to set the basis:
1503
parent_trees = [(revision, to_tree)]
1504
merges = self.get_parent_ids()[1:]
1505
# Ideally we ask the tree for the trees here, that way the working
1506
# tree can decide whether to give us the entire tree or give us a
1507
# lazy initialised tree. dirstate for instance will have the trees
1508
# in ram already, whereas a last-revision + basis-inventory tree
1509
# will not, but also does not need them when setting parents.
1510
for parent in merges:
1511
parent_trees.append(
1512
(parent, self.branch.repository.revision_tree(parent)))
1513
if not _mod_revision.is_null(old_tip):
1514
parent_trees.append(
1515
(old_tip, self.branch.repository.revision_tree(old_tip)))
1516
self.set_parent_trees(parent_trees)
1517
last_rev = parent_trees[0][0]
1520
def set_conflicts(self, arg):
1521
raise errors.UnsupportedOperation(self.set_conflicts, self)
1523
def add_conflicts(self, arg):
1524
raise errors.UnsupportedOperation(self.add_conflicts, self)
1526
def conflicts(self):
1527
raise NotImplementedError(self.conflicts)
1529
def walkdirs(self, prefix=""):
1530
"""Walk the directories of this tree.
1532
returns a generator which yields items in the form:
1533
((curren_directory_path, fileid),
1534
[(file1_path, file1_name, file1_kind, (lstat), file1_id,
1537
This API returns a generator, which is only valid during the current
1538
tree transaction - within a single lock_read or lock_write duration.
1540
If the tree is not locked, it may cause an error to be raised,
1541
depending on the tree implementation.
1543
disk_top = self.abspath(prefix)
1544
if disk_top.endswith('/'):
1545
disk_top = disk_top[:-1]
1546
top_strip_len = len(disk_top) + 1
1547
inventory_iterator = self._walkdirs(prefix)
1548
disk_iterator = osutils.walkdirs(disk_top, prefix)
1550
current_disk = disk_iterator.next()
1551
disk_finished = False
1553
if not (e.errno == errno.ENOENT or
1554
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
1557
disk_finished = True
1559
current_inv = inventory_iterator.next()
1560
inv_finished = False
1561
except StopIteration:
1564
while not inv_finished or not disk_finished:
1566
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
1567
cur_disk_dir_content) = current_disk
1569
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
1570
cur_disk_dir_content) = ((None, None), None)
1571
if not disk_finished:
1572
# strip out .bzr dirs
1573
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
1574
len(cur_disk_dir_content) > 0):
1575
# osutils.walkdirs can be made nicer -
1576
# yield the path-from-prefix rather than the pathjoined
1578
bzrdir_loc = bisect_left(cur_disk_dir_content,
1580
if (bzrdir_loc < len(cur_disk_dir_content)
1581
and self.bzrdir.is_control_filename(
1582
cur_disk_dir_content[bzrdir_loc][0])):
1583
# we dont yield the contents of, or, .bzr itself.
1584
del cur_disk_dir_content[bzrdir_loc]
1586
# everything is unknown
1589
# everything is missing
1592
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
1594
# disk is before inventory - unknown
1595
dirblock = [(relpath, basename, kind, stat, None, None) for
1596
relpath, basename, kind, stat, top_path in
1597
cur_disk_dir_content]
1598
yield (cur_disk_dir_relpath, None), dirblock
1600
current_disk = disk_iterator.next()
1601
except StopIteration:
1602
disk_finished = True
1604
# inventory is before disk - missing.
1605
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
1606
for relpath, basename, dkind, stat, fileid, kind in
1608
yield (current_inv[0][0], current_inv[0][1]), dirblock
1610
current_inv = inventory_iterator.next()
1611
except StopIteration:
1614
# versioned present directory
1615
# merge the inventory and disk data together
1617
for relpath, subiterator in itertools.groupby(sorted(
1618
current_inv[1] + cur_disk_dir_content,
1619
key=operator.itemgetter(0)), operator.itemgetter(1)):
1620
path_elements = list(subiterator)
1621
if len(path_elements) == 2:
1622
inv_row, disk_row = path_elements
1623
# versioned, present file
1624
dirblock.append((inv_row[0],
1625
inv_row[1], disk_row[2],
1626
disk_row[3], inv_row[4],
1628
elif len(path_elements[0]) == 5:
1630
dirblock.append((path_elements[0][0],
1631
path_elements[0][1], path_elements[0][2],
1632
path_elements[0][3], None, None))
1633
elif len(path_elements[0]) == 6:
1634
# versioned, absent file.
1635
dirblock.append((path_elements[0][0],
1636
path_elements[0][1], 'unknown', None,
1637
path_elements[0][4], path_elements[0][5]))
1639
raise NotImplementedError('unreachable code')
1640
yield current_inv[0], dirblock
1642
current_inv = inventory_iterator.next()
1643
except StopIteration:
1646
current_disk = disk_iterator.next()
1647
except StopIteration:
1648
disk_finished = True
1650
def _walkdirs(self, prefix=""):
1651
"""Walk the directories of this tree.
1653
:param prefix: is used as the directrory to start with.
1654
:returns: a generator which yields items in the form::
1656
((curren_directory_path, fileid),
1657
[(file1_path, file1_name, file1_kind, None, file1_id,
1660
raise NotImplementedError(self._walkdirs)
1662
@needs_tree_write_lock
1663
def auto_resolve(self):
1664
"""Automatically resolve text conflicts according to contents.
1666
Only text conflicts are auto_resolvable. Files with no conflict markers
1667
are considered 'resolved', because bzr always puts conflict markers
1668
into files that have text conflicts. The corresponding .THIS .BASE and
1669
.OTHER files are deleted, as per 'resolve'.
1671
:return: a tuple of ConflictLists: (un_resolved, resolved).
1673
un_resolved = _mod_conflicts.ConflictList()
1674
resolved = _mod_conflicts.ConflictList()
1675
conflict_re = re.compile('^(<{7}|={7}|>{7})')
1676
for conflict in self.conflicts():
1677
if (conflict.typestring != 'text conflict' or
1678
self.kind(conflict.file_id) != 'file'):
1679
un_resolved.append(conflict)
1681
my_file = open(self.id2abspath(conflict.file_id), 'rb')
1683
for line in my_file:
1684
if conflict_re.search(line):
1685
un_resolved.append(conflict)
1688
resolved.append(conflict)
1691
resolved.remove_files(self)
1692
self.set_conflicts(un_resolved)
1693
return un_resolved, resolved
1695
def _validate(self):
1696
"""Validate internal structures.
1698
This is meant mostly for the test suite. To give it a chance to detect
1699
corruption after actions have occurred. The default implementation is a
1702
:return: None. An exception should be raised if there is an error.
1706
def check_state(self):
1707
"""Check that the working state is/isn't valid."""
1708
raise NotImplementedError(self.check_state)
1710
def reset_state(self, revision_ids=None):
1711
"""Reset the state of the working tree.
1713
This does a hard-reset to a last-known-good state. This is a way to
1714
fix if something got corrupted (like the .bzr/checkout/dirstate file)
1716
raise NotImplementedError(self.reset_state)
1718
def _get_rules_searcher(self, default_searcher):
1719
"""See Tree._get_rules_searcher."""
1720
if self._rules_searcher is None:
1721
self._rules_searcher = super(WorkingTree,
1722
self)._get_rules_searcher(default_searcher)
1723
return self._rules_searcher
1725
def get_shelf_manager(self):
1726
"""Return the ShelfManager for this WorkingTree."""
1727
from bzrlib.shelf import ShelfManager
1728
return ShelfManager(self, self._transport)
1731
class InventoryWorkingTree(WorkingTree,
1732
bzrlib.mutabletree.MutableInventoryTree):
1733
"""Base class for working trees that are inventory-oriented.
1735
The inventory is held in the `Branch` working-inventory, and the
1736
files are in a directory on disk.
1738
It is possible for a `WorkingTree` to have a filename which is
1739
not listed in the Inventory and vice versa.
1742
def __init__(self, basedir='.',
1743
branch=DEPRECATED_PARAMETER,
1745
_control_files=None,
1749
"""Construct a InventoryWorkingTree instance. This is not a public API.
1751
:param branch: A branch to override probing for the branch.
1753
super(InventoryWorkingTree, self).__init__(basedir=basedir,
1754
branch=branch, _transport=_control_files._transport,
1755
_internal=_internal, _format=_format, _bzrdir=_bzrdir)
1757
self._control_files = _control_files
1758
self._detect_case_handling()
1760
if _inventory is None:
1761
# This will be acquired on lock_read() or lock_write()
1762
self._inventory_is_modified = False
1763
self._inventory = None
1765
# the caller of __init__ has provided an inventory,
1766
# we assume they know what they are doing - as its only
1767
# the Format factory and creation methods that are
1768
# permitted to do this.
1769
self._set_inventory(_inventory, dirty=False)
1771
def _set_inventory(self, inv, dirty):
1772
"""Set the internal cached inventory.
1774
:param inv: The inventory to set.
1775
:param dirty: A boolean indicating whether the inventory is the same
1776
logical inventory as whats on disk. If True the inventory is not
1777
the same and should be written to disk or data will be lost, if
1778
False then the inventory is the same as that on disk and any
1779
serialisation would be unneeded overhead.
1781
self._inventory = inv
1782
self._inventory_is_modified = dirty
1784
def _detect_case_handling(self):
1785
wt_trans = self.bzrdir.get_workingtree_transport(None)
1787
wt_trans.stat(self._format.case_sensitive_filename)
1788
except errors.NoSuchFile:
1789
self.case_sensitive = True
1791
self.case_sensitive = False
1793
self._setup_directory_is_tree_reference()
1795
def _serialize(self, inventory, out_file):
1796
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1799
def _deserialize(selt, in_file):
1800
return xml5.serializer_v5.read_inventory(in_file)
1802
def break_lock(self):
1803
"""Break a lock if one is present from another instance.
1805
Uses the ui factory to ask for confirmation if the lock may be from
1808
This will probe the repository for its lock as well.
1810
self._control_files.break_lock()
1811
self.branch.break_lock()
1813
def is_locked(self):
1814
return self._control_files.is_locked()
1816
def _must_be_locked(self):
1817
if not self.is_locked():
1818
raise errors.ObjectNotLocked(self)
1820
def lock_read(self):
1821
"""Lock the tree for reading.
1823
This also locks the branch, and can be unlocked via self.unlock().
1825
:return: A bzrlib.lock.LogicalLockResult.
1827
if not self.is_locked():
1829
self.branch.lock_read()
1831
self._control_files.lock_read()
1832
return LogicalLockResult(self.unlock)
1834
self.branch.unlock()
1837
def lock_tree_write(self):
1838
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1840
:return: A bzrlib.lock.LogicalLockResult.
1842
if not self.is_locked():
1844
self.branch.lock_read()
1846
self._control_files.lock_write()
1847
return LogicalLockResult(self.unlock)
1849
self.branch.unlock()
1852
def lock_write(self):
1853
"""See MutableTree.lock_write, and WorkingTree.unlock.
1855
:return: A bzrlib.lock.LogicalLockResult.
1857
if not self.is_locked():
1859
self.branch.lock_write()
1861
self._control_files.lock_write()
1862
return LogicalLockResult(self.unlock)
1864
self.branch.unlock()
1867
def get_physical_lock_status(self):
1868
return self._control_files.get_physical_lock_status()
1870
@needs_tree_write_lock
1871
def _write_inventory(self, inv):
1872
"""Write inventory as the current inventory."""
1873
self._set_inventory(inv, dirty=True)
1876
# XXX: This method should be deprecated in favour of taking in a proper
1877
# new Inventory object.
1878
@needs_tree_write_lock
1879
def set_inventory(self, new_inventory_list):
1880
from bzrlib.inventory import (Inventory,
1884
inv = Inventory(self.get_root_id())
1885
for path, file_id, parent, kind in new_inventory_list:
1886
name = os.path.basename(path)
1889
# fixme, there should be a factory function inv,add_??
1890
if kind == 'directory':
1891
inv.add(InventoryDirectory(file_id, name, parent))
1892
elif kind == 'file':
1893
inv.add(InventoryFile(file_id, name, parent))
1894
elif kind == 'symlink':
1895
inv.add(InventoryLink(file_id, name, parent))
1897
raise errors.BzrError("unknown kind %r" % kind)
1898
self._write_inventory(inv)
1900
def _write_basis_inventory(self, xml):
1901
"""Write the basis inventory XML to the basis-inventory file"""
1902
path = self._basis_inventory_name()
1904
self._transport.put_file(path, sio,
1905
mode=self.bzrdir._get_file_mode())
1907
def _reset_data(self):
1908
"""Reset transient data that cannot be revalidated."""
1909
self._inventory_is_modified = False
1910
f = self._transport.get('inventory')
1912
result = self._deserialize(f)
1915
self._set_inventory(result, dirty=False)
1917
def _set_root_id(self, file_id):
1918
"""Set the root id for this tree, in a format specific manner.
1920
:param file_id: The file id to assign to the root. It must not be
1921
present in the current inventory or an error will occur. It must
1922
not be None, but rather a valid file id.
1924
inv = self._inventory
1925
orig_root_id = inv.root.file_id
1926
# TODO: it might be nice to exit early if there was nothing
1927
# to do, saving us from trigger a sync on unlock.
1928
self._inventory_is_modified = True
1929
# we preserve the root inventory entry object, but
1930
# unlinkit from the byid index
1931
del inv._byid[inv.root.file_id]
1932
inv.root.file_id = file_id
1933
# and link it into the index with the new changed id.
1934
inv._byid[inv.root.file_id] = inv.root
1935
# and finally update all children to reference the new id.
1936
# XXX: this should be safe to just look at the root.children
1937
# list, not the WHOLE INVENTORY.
1940
if entry.parent_id == orig_root_id:
1941
entry.parent_id = inv.root.file_id
1943
def all_file_ids(self):
1944
"""See Tree.iter_all_file_ids"""
1945
return set(self.inventory)
1947
@needs_tree_write_lock
1948
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
1949
"""See MutableTree.set_parent_trees."""
1950
parent_ids = [rev for (rev, tree) in parents_list]
1951
for revision_id in parent_ids:
1952
_mod_revision.check_not_reserved_id(revision_id)
1954
self._check_parents_for_ghosts(parent_ids,
1955
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
1957
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
1959
if len(parent_ids) == 0:
1960
leftmost_parent_id = _mod_revision.NULL_REVISION
1961
leftmost_parent_tree = None
1963
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
1965
if self._change_last_revision(leftmost_parent_id):
1966
if leftmost_parent_tree is None:
1967
# If we don't have a tree, fall back to reading the
1968
# parent tree from the repository.
1969
self._cache_basis_inventory(leftmost_parent_id)
1971
inv = leftmost_parent_tree.inventory
1972
xml = self._create_basis_xml_from_inventory(
1973
leftmost_parent_id, inv)
1974
self._write_basis_inventory(xml)
1975
self._set_merges_from_parent_ids(parent_ids)
1977
def _cache_basis_inventory(self, new_revision):
1978
"""Cache new_revision as the basis inventory."""
1979
# TODO: this should allow the ready-to-use inventory to be passed in,
1980
# as commit already has that ready-to-use [while the format is the
1983
# this double handles the inventory - unpack and repack -
1984
# but is easier to understand. We can/should put a conditional
1985
# in here based on whether the inventory is in the latest format
1986
# - perhaps we should repack all inventories on a repository
1988
# the fast path is to copy the raw xml from the repository. If the
1989
# xml contains 'revision_id="', then we assume the right
1990
# revision_id is set. We must check for this full string, because a
1991
# root node id can legitimately look like 'revision_id' but cannot
1993
xml = self.branch.repository._get_inventory_xml(new_revision)
1994
firstline = xml.split('\n', 1)[0]
1995
if (not 'revision_id="' in firstline or
1996
'format="7"' not in firstline):
1997
inv = self.branch.repository._serializer.read_inventory_from_string(
1999
xml = self._create_basis_xml_from_inventory(new_revision, inv)
2000
self._write_basis_inventory(xml)
2001
except (errors.NoSuchRevision, errors.RevisionNotPresent):
2004
def _basis_inventory_name(self):
2005
return 'basis-inventory-cache'
2007
def _create_basis_xml_from_inventory(self, revision_id, inventory):
2008
"""Create the text that will be saved in basis-inventory"""
2009
inventory.revision_id = revision_id
2010
return xml7.serializer_v7.write_inventory_to_string(inventory)
2012
@needs_tree_write_lock
2013
def set_conflicts(self, conflicts):
2014
self._put_rio('conflicts', conflicts.to_stanzas(),
2017
@needs_tree_write_lock
2018
def add_conflicts(self, new_conflicts):
2019
conflict_set = set(self.conflicts())
2020
conflict_set.update(set(list(new_conflicts)))
2021
self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
2022
key=_mod_conflicts.Conflict.sort_key)))
2025
def conflicts(self):
2027
confile = self._transport.get('conflicts')
2028
except errors.NoSuchFile:
2029
return _mod_conflicts.ConflictList()
2032
if confile.next() != CONFLICT_HEADER_1 + '\n':
2033
raise errors.ConflictFormatError()
2034
except StopIteration:
2035
raise errors.ConflictFormatError()
2036
reader = _mod_rio.RioReader(confile)
2037
return _mod_conflicts.ConflictList.from_stanzas(reader)
2041
def read_basis_inventory(self):
2042
"""Read the cached basis inventory."""
2043
path = self._basis_inventory_name()
2044
return self._transport.get_bytes(path)
2047
def read_working_inventory(self):
2048
"""Read the working inventory.
2050
:raises errors.InventoryModified: read_working_inventory will fail
2051
when the current in memory inventory has been modified.
2053
# conceptually this should be an implementation detail of the tree.
2054
# XXX: Deprecate this.
2055
# ElementTree does its own conversion from UTF-8, so open in
2057
if self._inventory_is_modified:
2058
raise errors.InventoryModified(self)
2059
f = self._transport.get('inventory')
2061
result = self._deserialize(f)
2064
self._set_inventory(result, dirty=False)
2068
def get_root_id(self):
2069
"""Return the id of this trees root"""
2070
return self._inventory.root.file_id
2072
def has_id(self, file_id):
2073
# files that have been deleted are excluded
2074
inv = self.inventory
2075
if not inv.has_id(file_id):
2077
path = inv.id2path(file_id)
2078
return osutils.lexists(self.abspath(path))
2080
def has_or_had_id(self, file_id):
2081
if file_id == self.inventory.root.file_id:
2083
return self.inventory.has_id(file_id)
2085
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2087
"""Iterate through file_ids for this tree.
2089
file_ids are in a WorkingTree if they are in the working inventory
2090
and the working file exists.
2092
inv = self._inventory
2093
for path, ie in inv.iter_entries():
2094
if osutils.lexists(self.abspath(path)):
2097
@needs_tree_write_lock
2098
def set_last_revision(self, new_revision):
2099
"""Change the last revision in the working tree."""
2100
if self._change_last_revision(new_revision):
2101
self._cache_basis_inventory(new_revision)
2103
def _get_check_refs(self):
2104
"""Return the references needed to perform a check of this tree.
2106
The default implementation returns no refs, and is only suitable for
2107
trees that have no local caching and can commit on ghosts at any time.
2109
:seealso: bzrlib.check for details about check_refs.
2114
def _check(self, references):
2115
"""Check the tree for consistency.
2117
:param references: A dict with keys matching the items returned by
2118
self._get_check_refs(), and values from looking those keys up in
2121
tree_basis = self.basis_tree()
2122
tree_basis.lock_read()
2124
repo_basis = references[('trees', self.last_revision())]
2125
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2126
raise errors.BzrCheckError(
2127
"Mismatched basis inventory content.")
2133
def check_state(self):
2134
"""Check that the working state is/isn't valid."""
2135
check_refs = self._get_check_refs()
2137
for ref in check_refs:
2140
refs[ref] = self.branch.repository.revision_tree(value)
2143
@needs_tree_write_lock
2144
def reset_state(self, revision_ids=None):
2145
"""Reset the state of the working tree.
2147
This does a hard-reset to a last-known-good state. This is a way to
2148
fix if something got corrupted (like the .bzr/checkout/dirstate file)
2150
if revision_ids is None:
2151
revision_ids = self.get_parent_ids()
2152
if not revision_ids:
2153
rt = self.branch.repository.revision_tree(
2154
_mod_revision.NULL_REVISION)
2156
rt = self.branch.repository.revision_tree(revision_ids[0])
2157
self._write_inventory(rt.inventory)
2158
self.set_parent_ids(revision_ids)
2161
"""Write the in memory inventory to disk."""
2162
# TODO: Maybe this should only write on dirty ?
2163
if self._control_files._lock_mode != 'w':
2164
raise errors.NotWriteLocked(self)
2166
self._serialize(self._inventory, sio)
2168
self._transport.put_file('inventory', sio,
2169
mode=self.bzrdir._get_file_mode())
2170
self._inventory_is_modified = False
2172
def get_file_mtime(self, file_id, path=None):
2173
"""See Tree.get_file_mtime."""
2175
path = self.inventory.id2path(file_id)
2177
return os.lstat(self.abspath(path)).st_mtime
2179
if e.errno == errno.ENOENT:
2180
raise errors.FileTimestampUnavailable(path)
2183
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2184
file_id = self.path2id(path)
2186
# For unversioned files on win32, we just assume they are not
2189
return self._inventory[file_id].executable
2191
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2192
mode = stat_result.st_mode
2193
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2195
if not supports_executable():
2196
def is_executable(self, file_id, path=None):
2197
return self._inventory[file_id].executable
2199
_is_executable_from_path_and_stat = \
2200
_is_executable_from_path_and_stat_from_basis
2202
def is_executable(self, file_id, path=None):
2204
path = self.id2path(file_id)
2205
mode = os.lstat(self.abspath(path)).st_mode
2206
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2208
_is_executable_from_path_and_stat = \
2209
_is_executable_from_path_and_stat_from_stat
2211
@needs_tree_write_lock
2212
def _add(self, files, ids, kinds):
2213
"""See MutableTree._add."""
2214
# TODO: Re-adding a file that is removed in the working copy
2215
# should probably put it back with the previous ID.
2216
# the read and write working inventory should not occur in this
2217
# function - they should be part of lock_write and unlock.
2218
inv = self.inventory
2219
for f, file_id, kind in zip(files, ids, kinds):
2221
inv.add_path(f, kind=kind)
2223
inv.add_path(f, kind=kind, file_id=file_id)
2224
self._inventory_is_modified = True
2226
def revision_tree(self, revision_id):
2227
"""See WorkingTree.revision_id."""
2228
if revision_id == self.last_revision():
2230
xml = self.read_basis_inventory()
2231
except errors.NoSuchFile:
2235
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2236
# dont use the repository revision_tree api because we want
2237
# to supply the inventory.
2238
if inv.revision_id == revision_id:
2239
return revisiontree.InventoryRevisionTree(
2240
self.branch.repository, inv, revision_id)
2241
except errors.BadInventoryFormat:
2243
# raise if there was no inventory, or if we read the wrong inventory.
2244
raise errors.NoSuchRevisionInTree(self, revision_id)
2247
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
2248
"""See Tree.annotate_iter
2250
This implementation will use the basis tree implementation if possible.
2251
Lines not in the basis are attributed to CURRENT_REVISION
2253
If there are pending merges, lines added by those merges will be
2254
incorrectly attributed to CURRENT_REVISION (but after committing, the
2255
attribution will be correct).
2257
maybe_file_parent_keys = []
2258
for parent_id in self.get_parent_ids():
2260
parent_tree = self.revision_tree(parent_id)
2261
except errors.NoSuchRevisionInTree:
2262
parent_tree = self.branch.repository.revision_tree(parent_id)
2263
parent_tree.lock_read()
2265
if not parent_tree.has_id(file_id):
2267
ie = parent_tree.inventory[file_id]
2268
if ie.kind != 'file':
2269
# Note: this is slightly unnecessary, because symlinks and
2270
# directories have a "text" which is the empty text, and we
2271
# know that won't mess up annotations. But it seems cleaner
2273
parent_text_key = (file_id, ie.revision)
2274
if parent_text_key not in maybe_file_parent_keys:
2275
maybe_file_parent_keys.append(parent_text_key)
2277
parent_tree.unlock()
2278
graph = _mod_graph.Graph(self.branch.repository.texts)
2279
heads = graph.heads(maybe_file_parent_keys)
2280
file_parent_keys = []
2281
for key in maybe_file_parent_keys:
2283
file_parent_keys.append(key)
2285
# Now we have the parents of this content
2286
annotator = self.branch.repository.texts.get_annotator()
2287
text = self.get_file_text(file_id)
2288
this_key =(file_id, default_revision)
2289
annotator.add_special_text(this_key, file_parent_keys, text)
2290
annotations = [(key[-1], line)
2291
for key, line in annotator.annotate_flat(this_key)]
2294
def _put_rio(self, filename, stanzas, header):
2295
self._must_be_locked()
2296
my_file = _mod_rio.rio_file(stanzas, header)
2297
self._transport.put_file(filename, my_file,
2298
mode=self.bzrdir._get_file_mode())
2300
@needs_tree_write_lock
2301
def set_merge_modified(self, modified_hashes):
2303
for file_id, hash in modified_hashes.iteritems():
2304
yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
2306
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
2309
def merge_modified(self):
2310
"""Return a dictionary of files modified by a merge.
2312
The list is initialized by WorkingTree.set_merge_modified, which is
2313
typically called after we make some automatic updates to the tree
2316
This returns a map of file_id->sha1, containing only files which are
2317
still in the working inventory and have that text hash.
2320
hashfile = self._transport.get('merge-hashes')
2321
except errors.NoSuchFile:
2326
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
2327
raise errors.MergeModifiedFormatError()
2328
except StopIteration:
2329
raise errors.MergeModifiedFormatError()
2330
for s in _mod_rio.RioReader(hashfile):
2331
# RioReader reads in Unicode, so convert file_ids back to utf8
2332
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2333
if not self.inventory.has_id(file_id):
2335
text_hash = s.get("hash")
2336
if text_hash == self.get_file_sha1(file_id):
2337
merge_hashes[file_id] = text_hash
2343
def subsume(self, other_tree):
2344
def add_children(inventory, entry):
2345
for child_entry in entry.children.values():
2346
inventory._byid[child_entry.file_id] = child_entry
2347
if child_entry.kind == 'directory':
2348
add_children(inventory, child_entry)
2349
if other_tree.get_root_id() == self.get_root_id():
2350
raise errors.BadSubsumeSource(self, other_tree,
2351
'Trees have the same root')
2353
other_tree_path = self.relpath(other_tree.basedir)
2354
except errors.PathNotChild:
2355
raise errors.BadSubsumeSource(self, other_tree,
2356
'Tree is not contained by the other')
2357
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
2358
if new_root_parent is None:
2359
raise errors.BadSubsumeSource(self, other_tree,
2360
'Parent directory is not versioned.')
2361
# We need to ensure that the result of a fetch will have a
2362
# versionedfile for the other_tree root, and only fetching into
2363
# RepositoryKnit2 guarantees that.
2364
if not self.branch.repository.supports_rich_root():
2365
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
2366
other_tree.lock_tree_write()
2368
new_parents = other_tree.get_parent_ids()
2369
other_root = other_tree.inventory.root
2370
other_root.parent_id = new_root_parent
2371
other_root.name = osutils.basename(other_tree_path)
2372
self.inventory.add(other_root)
2373
add_children(self.inventory, other_root)
2374
self._write_inventory(self.inventory)
2375
# normally we don't want to fetch whole repositories, but i think
2376
# here we really do want to consolidate the whole thing.
2377
for parent_id in other_tree.get_parent_ids():
2378
self.branch.fetch(other_tree.branch, parent_id)
2379
self.add_parent_tree_id(parent_id)
2382
other_tree.bzrdir.retire_bzrdir()
2384
@needs_tree_write_lock
2385
def extract(self, file_id, format=None):
2386
"""Extract a subtree from this tree.
2388
A new branch will be created, relative to the path for this tree.
2392
segments = osutils.splitpath(path)
2393
transport = self.branch.bzrdir.root_transport
2394
for name in segments:
2395
transport = transport.clone(name)
2396
transport.ensure_base()
2399
sub_path = self.id2path(file_id)
2400
branch_transport = mkdirs(sub_path)
2402
format = self.bzrdir.cloning_metadir()
2403
branch_transport.ensure_base()
2404
branch_bzrdir = format.initialize_on_transport(branch_transport)
2406
repo = branch_bzrdir.find_repository()
2407
except errors.NoRepositoryPresent:
2408
repo = branch_bzrdir.create_repository()
2409
if not repo.supports_rich_root():
2410
raise errors.RootNotRich()
2411
new_branch = branch_bzrdir.create_branch()
2412
new_branch.pull(self.branch)
2413
for parent_id in self.get_parent_ids():
2414
new_branch.fetch(self.branch, parent_id)
2415
tree_transport = self.bzrdir.root_transport.clone(sub_path)
2416
if tree_transport.base != branch_transport.base:
2417
tree_bzrdir = format.initialize_on_transport(tree_transport)
2418
branch.BranchReferenceFormat().initialize(tree_bzrdir,
2419
target_branch=new_branch)
2421
tree_bzrdir = branch_bzrdir
2422
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2423
wt.set_parent_ids(self.get_parent_ids())
2424
my_inv = self.inventory
2425
child_inv = inventory.Inventory(root_id=None)
2426
new_root = my_inv[file_id]
2427
my_inv.remove_recursive_id(file_id)
2428
new_root.parent_id = None
2429
child_inv.add(new_root)
2430
self._write_inventory(my_inv)
2431
wt._write_inventory(child_inv)
2434
def list_files(self, include_root=False, from_dir=None, recursive=True):
2435
"""List all files as (path, class, kind, id, entry).
2437
Lists, but does not descend into unversioned directories.
2438
This does not include files that have been deleted in this
2439
tree. Skips the control directory.
2441
:param include_root: if True, return an entry for the root
2442
:param from_dir: start from this directory or None for the root
2443
:param recursive: whether to recurse into subdirectories or not
2445
# list_files is an iterator, so @needs_read_lock doesn't work properly
2446
# with it. So callers should be careful to always read_lock the tree.
2447
if not self.is_locked():
2448
raise errors.ObjectNotLocked(self)
2450
inv = self.inventory
2451
if from_dir is None and include_root is True:
2452
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
2453
# Convert these into local objects to save lookup times
2454
pathjoin = osutils.pathjoin
2455
file_kind = self._kind
2457
# transport.base ends in a slash, we want the piece
2458
# between the last two slashes
2459
transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
2461
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
2463
# directory file_id, relative path, absolute path, reverse sorted children
2464
if from_dir is not None:
2465
from_dir_id = inv.path2id(from_dir)
2466
if from_dir_id is None:
2467
# Directory not versioned
2469
from_dir_abspath = pathjoin(self.basedir, from_dir)
2471
from_dir_id = inv.root.file_id
2472
from_dir_abspath = self.basedir
2473
children = os.listdir(from_dir_abspath)
2475
# jam 20060527 The kernel sized tree seems equivalent whether we
2476
# use a deque and popleft to keep them sorted, or if we use a plain
2477
# list and just reverse() them.
2478
children = collections.deque(children)
2479
stack = [(from_dir_id, u'', from_dir_abspath, children)]
2481
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
2484
f = children.popleft()
2485
## TODO: If we find a subdirectory with its own .bzr
2486
## directory, then that is a separate tree and we
2487
## should exclude it.
2489
# the bzrdir for this tree
2490
if transport_base_dir == f:
2493
# we know that from_dir_relpath and from_dir_abspath never end in a slash
2494
# and 'f' doesn't begin with one, we can do a string op, rather
2495
# than the checks of pathjoin(), all relative paths will have an extra slash
2497
fp = from_dir_relpath + '/' + f
2500
fap = from_dir_abspath + '/' + f
2502
dir_ie = inv[from_dir_id]
2503
if dir_ie.kind == 'directory':
2504
f_ie = dir_ie.children.get(f)
2509
elif self.is_ignored(fp[1:]):
2512
# we may not have found this file, because of a unicode
2513
# issue, or because the directory was actually a symlink.
2514
f_norm, can_access = osutils.normalized_filename(f)
2515
if f == f_norm or not can_access:
2516
# No change, so treat this file normally
2519
# this file can be accessed by a normalized path
2520
# check again if it is versioned
2521
# these lines are repeated here for performance
2523
fp = from_dir_relpath + '/' + f
2524
fap = from_dir_abspath + '/' + f
2525
f_ie = inv.get_child(from_dir_id, f)
2528
elif self.is_ignored(fp[1:]):
2535
# make a last minute entry
2537
yield fp[1:], c, fk, f_ie.file_id, f_ie
2540
yield fp[1:], c, fk, None, fk_entries[fk]()
2542
yield fp[1:], c, fk, None, TreeEntry()
2545
if fk != 'directory':
2548
# But do this child first if recursing down
2550
new_children = os.listdir(fap)
2552
new_children = collections.deque(new_children)
2553
stack.append((f_ie.file_id, fp, fap, new_children))
2554
# Break out of inner loop,
2555
# so that we start outer loop with child
2558
# if we finished all children, pop it off the stack
2561
@needs_tree_write_lock
2562
def move(self, from_paths, to_dir=None, after=False):
2565
to_dir must exist in the inventory.
2567
If to_dir exists and is a directory, the files are moved into
2568
it, keeping their old names.
2570
Note that to_dir is only the last component of the new name;
2571
this doesn't change the directory.
2573
For each entry in from_paths the move mode will be determined
2576
The first mode moves the file in the filesystem and updates the
2577
inventory. The second mode only updates the inventory without
2578
touching the file on the filesystem.
2580
move uses the second mode if 'after == True' and the target is
2581
either not versioned or newly added, and present in the working tree.
2583
move uses the second mode if 'after == False' and the source is
2584
versioned but no longer in the working tree, and the target is not
2585
versioned but present in the working tree.
2587
move uses the first mode if 'after == False' and the source is
2588
versioned and present in the working tree, and the target is not
2589
versioned and not present in the working tree.
2591
Everything else results in an error.
2593
This returns a list of (from_path, to_path) pairs for each
2594
entry that is moved.
2599
# check for deprecated use of signature
2601
raise TypeError('You must supply a target directory')
2602
# check destination directory
2603
if isinstance(from_paths, basestring):
2605
inv = self.inventory
2606
to_abs = self.abspath(to_dir)
2607
if not isdir(to_abs):
2608
raise errors.BzrMoveFailedError('',to_dir,
2609
errors.NotADirectory(to_abs))
2610
if not self.has_filename(to_dir):
2611
raise errors.BzrMoveFailedError('',to_dir,
2612
errors.NotInWorkingDirectory(to_dir))
2613
to_dir_id = inv.path2id(to_dir)
2614
if to_dir_id is None:
2615
raise errors.BzrMoveFailedError('',to_dir,
2616
errors.NotVersionedError(path=to_dir))
2618
to_dir_ie = inv[to_dir_id]
2619
if to_dir_ie.kind != 'directory':
2620
raise errors.BzrMoveFailedError('',to_dir,
2621
errors.NotADirectory(to_abs))
2623
# create rename entries and tuples
2624
for from_rel in from_paths:
2625
from_tail = splitpath(from_rel)[-1]
2626
from_id = inv.path2id(from_rel)
2628
raise errors.BzrMoveFailedError(from_rel,to_dir,
2629
errors.NotVersionedError(path=from_rel))
2631
from_entry = inv[from_id]
2632
from_parent_id = from_entry.parent_id
2633
to_rel = pathjoin(to_dir, from_tail)
2634
rename_entry = InventoryWorkingTree._RenameEntry(
2637
from_tail=from_tail,
2638
from_parent_id=from_parent_id,
2639
to_rel=to_rel, to_tail=from_tail,
2640
to_parent_id=to_dir_id)
2641
rename_entries.append(rename_entry)
2642
rename_tuples.append((from_rel, to_rel))
2644
# determine which move mode to use. checks also for movability
2645
rename_entries = self._determine_mv_mode(rename_entries, after)
2647
original_modified = self._inventory_is_modified
2650
self._inventory_is_modified = True
2651
self._move(rename_entries)
2653
# restore the inventory on error
2654
self._inventory_is_modified = original_modified
2656
self._write_inventory(inv)
2657
return rename_tuples
2659
@needs_tree_write_lock
2660
def rename_one(self, from_rel, to_rel, after=False):
2663
This can change the directory or the filename or both.
2665
rename_one has several 'modes' to work. First, it can rename a physical
2666
file and change the file_id. That is the normal mode. Second, it can
2667
only change the file_id without touching any physical file.
2669
rename_one uses the second mode if 'after == True' and 'to_rel' is not
2670
versioned but present in the working tree.
2672
rename_one uses the second mode if 'after == False' and 'from_rel' is
2673
versioned but no longer in the working tree, and 'to_rel' is not
2674
versioned but present in the working tree.
2676
rename_one uses the first mode if 'after == False' and 'from_rel' is
2677
versioned and present in the working tree, and 'to_rel' is not
2678
versioned and not present in the working tree.
2680
Everything else results in an error.
2682
inv = self.inventory
2685
# create rename entries and tuples
2686
from_tail = splitpath(from_rel)[-1]
2687
from_id = inv.path2id(from_rel)
2689
# if file is missing in the inventory maybe it's in the basis_tree
2690
basis_tree = self.branch.basis_tree()
2691
from_id = basis_tree.path2id(from_rel)
2693
raise errors.BzrRenameFailedError(from_rel,to_rel,
2694
errors.NotVersionedError(path=from_rel))
2695
# put entry back in the inventory so we can rename it
2696
from_entry = basis_tree.inventory[from_id].copy()
2699
from_entry = inv[from_id]
2700
from_parent_id = from_entry.parent_id
2701
to_dir, to_tail = os.path.split(to_rel)
2702
to_dir_id = inv.path2id(to_dir)
2703
rename_entry = InventoryWorkingTree._RenameEntry(from_rel=from_rel,
2705
from_tail=from_tail,
2706
from_parent_id=from_parent_id,
2707
to_rel=to_rel, to_tail=to_tail,
2708
to_parent_id=to_dir_id)
2709
rename_entries.append(rename_entry)
2711
# determine which move mode to use. checks also for movability
2712
rename_entries = self._determine_mv_mode(rename_entries, after)
2714
# check if the target changed directory and if the target directory is
2716
if to_dir_id is None:
2717
raise errors.BzrMoveFailedError(from_rel,to_rel,
2718
errors.NotVersionedError(path=to_dir))
2720
# all checks done. now we can continue with our actual work
2721
mutter('rename_one:\n'
2726
' to_dir_id {%s}\n',
2727
from_id, from_rel, to_rel, to_dir, to_dir_id)
2729
self._move(rename_entries)
2730
self._write_inventory(inv)
2732
class _RenameEntry(object):
2733
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2734
to_rel, to_tail, to_parent_id, only_change_inv=False,
2736
self.from_rel = from_rel
2737
self.from_id = from_id
2738
self.from_tail = from_tail
2739
self.from_parent_id = from_parent_id
2740
self.to_rel = to_rel
2741
self.to_tail = to_tail
2742
self.to_parent_id = to_parent_id
2743
self.change_id = change_id
2744
self.only_change_inv = only_change_inv
2746
def _determine_mv_mode(self, rename_entries, after=False):
2747
"""Determines for each from-to pair if both inventory and working tree
2748
or only the inventory has to be changed.
2750
Also does basic plausability tests.
2752
inv = self.inventory
2754
for rename_entry in rename_entries:
2755
# store to local variables for easier reference
2756
from_rel = rename_entry.from_rel
2757
from_id = rename_entry.from_id
2758
to_rel = rename_entry.to_rel
2759
to_id = inv.path2id(to_rel)
2760
only_change_inv = False
2763
# check the inventory for source and destination
2765
raise errors.BzrMoveFailedError(from_rel,to_rel,
2766
errors.NotVersionedError(path=from_rel))
2767
if to_id is not None:
2769
# allow it with --after but only if dest is newly added
2771
basis = self.basis_tree()
2774
if not basis.has_id(to_id):
2775
rename_entry.change_id = True
2780
raise errors.BzrMoveFailedError(from_rel,to_rel,
2781
errors.AlreadyVersionedError(path=to_rel))
2783
# try to determine the mode for rename (only change inv or change
2784
# inv and file system)
2786
if not self.has_filename(to_rel):
2787
raise errors.BzrMoveFailedError(from_id,to_rel,
2788
errors.NoSuchFile(path=to_rel,
2789
extra="New file has not been created yet"))
2790
only_change_inv = True
2791
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
2792
only_change_inv = True
2793
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
2794
only_change_inv = False
2795
elif (not self.case_sensitive
2796
and from_rel.lower() == to_rel.lower()
2797
and self.has_filename(from_rel)):
2798
only_change_inv = False
2800
# something is wrong, so lets determine what exactly
2801
if not self.has_filename(from_rel) and \
2802
not self.has_filename(to_rel):
2803
raise errors.BzrRenameFailedError(from_rel, to_rel,
2804
errors.PathsDoNotExist(paths=(from_rel, to_rel)))
2806
raise errors.RenameFailedFilesExist(from_rel, to_rel)
2807
rename_entry.only_change_inv = only_change_inv
2808
return rename_entries
2810
def _move(self, rename_entries):
2811
"""Moves a list of files.
2813
Depending on the value of the flag 'only_change_inv', the
2814
file will be moved on the file system or not.
2816
inv = self.inventory
2819
for entry in rename_entries:
2821
self._move_entry(entry)
2823
self._rollback_move(moved)
2827
def _rollback_move(self, moved):
2828
"""Try to rollback a previous move in case of an filesystem error."""
2829
inv = self.inventory
2832
self._move_entry(WorkingTree._RenameEntry(
2833
entry.to_rel, entry.from_id,
2834
entry.to_tail, entry.to_parent_id, entry.from_rel,
2835
entry.from_tail, entry.from_parent_id,
2836
entry.only_change_inv))
2837
except errors.BzrMoveFailedError, e:
2838
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
2839
" The working tree is in an inconsistent state."
2840
" Please consider doing a 'bzr revert'."
2841
" Error message is: %s" % e)
2843
def _move_entry(self, entry):
2844
inv = self.inventory
2845
from_rel_abs = self.abspath(entry.from_rel)
2846
to_rel_abs = self.abspath(entry.to_rel)
2847
if from_rel_abs == to_rel_abs:
2848
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
2849
"Source and target are identical.")
2851
if not entry.only_change_inv:
2853
osutils.rename(from_rel_abs, to_rel_abs)
2855
raise errors.BzrMoveFailedError(entry.from_rel,
2858
to_id = inv.path2id(entry.to_rel)
2859
inv.remove_recursive_id(to_id)
2860
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
2862
@needs_tree_write_lock
2863
def unversion(self, file_ids):
2864
"""Remove the file ids in file_ids from the current versioned set.
2866
When a file_id is unversioned, all of its children are automatically
2869
:param file_ids: The file ids to stop versioning.
2870
:raises: NoSuchId if any fileid is not currently versioned.
2872
for file_id in file_ids:
2873
if not self._inventory.has_id(file_id):
2874
raise errors.NoSuchId(self, file_id)
2875
for file_id in file_ids:
2876
if self._inventory.has_id(file_id):
2877
self._inventory.remove_recursive_id(file_id)
2879
# in the future this should just set a dirty bit to wait for the
2880
# final unlock. However, until all methods of workingtree start
2881
# with the current in -memory inventory rather than triggering
2882
# a read, it is more complex - we need to teach read_inventory
2883
# to know when to read, and when to not read first... and possibly
2884
# to save first when the in memory one may be corrupted.
2885
# so for now, we just only write it if it is indeed dirty.
2887
self._write_inventory(self._inventory)
2889
def stored_kind(self, file_id):
2890
"""See Tree.stored_kind"""
2891
return self.inventory[file_id].kind
2894
"""Yield all unversioned files in this WorkingTree.
2896
If there are any unversioned directories then only the directory is
2897
returned, not all its children. But if there are unversioned files
2898
under a versioned subdirectory, they are returned.
2900
Currently returned depth-first, sorted by name within directories.
2901
This is the same order used by 'osutils.walkdirs'.
2903
## TODO: Work from given directory downwards
2904
for path, dir_entry in self.inventory.directories():
2905
# mutter("search for unknowns in %r", path)
2906
dirabs = self.abspath(path)
2907
if not isdir(dirabs):
2908
# e.g. directory deleted
2912
for subf in os.listdir(dirabs):
2913
if self.bzrdir.is_control_filename(subf):
2915
if subf not in dir_entry.children:
2918
can_access) = osutils.normalized_filename(subf)
2919
except UnicodeDecodeError:
2920
path_os_enc = path.encode(osutils._fs_enc)
2921
relpath = path_os_enc + '/' + subf
2922
raise errors.BadFilenameEncoding(relpath,
2924
if subf_norm != subf and can_access:
2925
if subf_norm not in dir_entry.children:
2926
fl.append(subf_norm)
2932
subp = pathjoin(path, subf)
2935
def _walkdirs(self, prefix=""):
2936
"""Walk the directories of this tree.
2938
:param prefix: is used as the directrory to start with.
2939
:returns: a generator which yields items in the form::
2941
((curren_directory_path, fileid),
2942
[(file1_path, file1_name, file1_kind, None, file1_id,
2945
_directory = 'directory'
2946
# get the root in the inventory
2947
inv = self.inventory
2948
top_id = inv.path2id(prefix)
2952
pending = [(prefix, '', _directory, None, top_id, None)]
2955
currentdir = pending.pop()
2956
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2957
top_id = currentdir[4]
2959
relroot = currentdir[0] + '/'
2962
# FIXME: stash the node in pending
2964
if entry.kind == 'directory':
2965
for name, child in entry.sorted_children():
2966
dirblock.append((relroot + name, name, child.kind, None,
2967
child.file_id, child.kind
2969
yield (currentdir[0], entry.file_id), dirblock
2970
# push the user specified dirs from dirblock
2971
for dir in reversed(dirblock):
2972
if dir[2] == _directory:
2976
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2977
"""Registry for working tree formats."""
2979
def __init__(self, other_registry=None):
2980
super(WorkingTreeFormatRegistry, self).__init__(other_registry)
2981
self._default_format = None
2982
self._default_format_key = None
2984
def get_default(self):
2985
"""Return the current default format."""
2986
if (self._default_format_key is not None and
2987
self._default_format is None):
2988
self._default_format = self.get(self._default_format_key)
2989
return self._default_format
2991
def set_default(self, format):
2992
"""Set the default format."""
2993
self._default_format = format
2994
self._default_format_key = None
2996
def set_default_key(self, format_string):
2997
"""Set the default format by its format string."""
2998
self._default_format_key = format_string
2999
self._default_format = None
3002
format_registry = WorkingTreeFormatRegistry()
3005
class WorkingTreeFormat(controldir.ControlComponentFormat):
3006
"""An encapsulation of the initialization and open routines for a format.
3008
Formats provide three things:
3009
* An initialization routine,
3013
Formats are placed in an dict by their format string for reference
3014
during workingtree opening. Its not required that these be instances, they
3015
can be classes themselves with class methods - it simply depends on
3016
whether state is needed for a given format or not.
3018
Once a format is deprecated, just deprecate the initialize and open
3019
methods on the format class. Do not deprecate the object, as the
3020
object will be created every time regardless.
3023
requires_rich_root = False
3025
upgrade_recommended = False
3027
requires_normalized_unicode_filenames = False
3029
case_sensitive_filename = "FoRMaT"
3031
missing_parent_conflicts = False
3032
"""If this format supports missing parent conflicts."""
3034
supports_versioned_directories = None
3036
def initialize(self, controldir, revision_id=None, from_branch=None,
3037
accelerator_tree=None, hardlink=False):
3038
"""Initialize a new working tree in controldir.
3040
:param controldir: ControlDir to initialize the working tree in.
3041
:param revision_id: allows creating a working tree at a different
3042
revision than the branch is at.
3043
:param from_branch: Branch to checkout
3044
:param accelerator_tree: A tree which can be used for retrieving file
3045
contents more quickly than the revision tree, i.e. a workingtree.
3046
The revision tree will be used for cases where accelerator_tree's
3047
content is different.
3048
:param hardlink: If true, hard-link files from accelerator_tree,
3051
raise NotImplementedError(self.initialize)
3053
def __eq__(self, other):
3054
return self.__class__ is other.__class__
3056
def __ne__(self, other):
3057
return not (self == other)
3060
@symbol_versioning.deprecated_method(
3061
symbol_versioning.deprecated_in((2, 4, 0)))
3062
def get_default_format(klass):
3063
"""Return the current default format."""
3064
return format_registry.get_default()
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)
3123
def get_controldir_for_branch(self):
3124
"""Get the control directory format for creating branches.
3126
This is to support testing of working tree formats that can not exist
3127
in the same control directory as a branch.
3129
return self._matchingbzrdir
3132
class WorkingTreeFormatMetaDir(bzrdir.BzrDirMetaComponentFormat, WorkingTreeFormat):
3133
"""Base class for working trees that live in bzr meta directories."""
3136
WorkingTreeFormat.__init__(self)
3137
bzrdir.BzrDirMetaComponentFormat.__init__(self)
3140
def find_format_string(klass, controldir):
3141
"""Return format name for the working tree object in controldir."""
3143
transport = controldir.get_workingtree_transport(None)
3144
return transport.get_bytes("format")
3145
except errors.NoSuchFile:
3146
raise errors.NoWorkingTree(base=transport.base)
3149
def find_format(klass, controldir):
3150
"""Return the format for the working tree object in controldir."""
3151
format_string = klass.find_format_string(controldir)
3152
return klass._find_format(format_registry, 'working tree',
3156
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3157
"bzrlib.workingtree_4", "WorkingTreeFormat4")
3158
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3159
"bzrlib.workingtree_4", "WorkingTreeFormat5")
3160
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3161
"bzrlib.workingtree_4", "WorkingTreeFormat6")
3162
format_registry.register_lazy("Bazaar-NG Working Tree format 3",
3163
"bzrlib.workingtree_3", "WorkingTreeFormat3")
3164
format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")