~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: John Arbash Meinel
  • Date: 2011-04-20 15:06:17 UTC
  • mto: This revision was merged to the branch mainline in revision 5836.
  • Revision ID: john@arbash-meinel.com-20110420150617-i41caxgemg32tq1r
Start adding tests that _worth_saving_limit works as expected.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
WorkingTree.open(dir).
30
30
"""
31
31
 
32
 
from __future__ import absolute_import
33
32
 
34
33
from cStringIO import StringIO
35
34
import os
47
46
 
48
47
from bzrlib import (
49
48
    branch,
 
49
    bzrdir,
50
50
    conflicts as _mod_conflicts,
51
51
    controldir,
52
52
    errors,
54
54
    generate_ids,
55
55
    globbing,
56
56
    graph as _mod_graph,
 
57
    hashcache,
57
58
    ignores,
58
59
    inventory,
59
60
    merge,
60
61
    revision as _mod_revision,
61
62
    revisiontree,
62
63
    rio as _mod_rio,
63
 
    shelf,
64
64
    transform,
65
65
    transport,
66
66
    ui,
68
68
    xml5,
69
69
    xml7,
70
70
    )
 
71
from bzrlib.workingtree_4 import (
 
72
    WorkingTreeFormat4,
 
73
    WorkingTreeFormat5,
 
74
    WorkingTreeFormat6,
 
75
    )
71
76
""")
72
77
 
73
 
# Explicitly import bzrlib.bzrdir so that the BzrProber
74
 
# is guaranteed to be registered.
75
 
from bzrlib import (
76
 
    bzrdir,
77
 
    symbol_versioning,
78
 
    )
79
 
 
 
78
from bzrlib import symbol_versioning
80
79
from bzrlib.decorators import needs_read_lock, needs_write_lock
81
 
from bzrlib.i18n import gettext
82
80
from bzrlib.lock import LogicalLockResult
 
81
from bzrlib.lockable_files import LockableFiles
 
82
from bzrlib.lockdir import LockDir
83
83
import bzrlib.mutabletree
84
84
from bzrlib.mutabletree import needs_tree_write_lock
85
85
from bzrlib import osutils
91
91
    realpath,
92
92
    safe_unicode,
93
93
    splitpath,
 
94
    supports_executable,
94
95
    )
95
96
from bzrlib.trace import mutter, note
 
97
from bzrlib.transport.local import LocalTransport
96
98
from bzrlib.revision import CURRENT_REVISION
97
99
from bzrlib.symbol_versioning import (
98
100
    deprecated_passed,
178
180
 
179
181
    def __init__(self, basedir='.',
180
182
                 branch=DEPRECATED_PARAMETER,
 
183
                 _control_files=None,
181
184
                 _internal=False,
182
 
                 _transport=None,
183
185
                 _format=None,
184
186
                 _bzrdir=None):
185
187
        """Construct a WorkingTree instance. This is not a public API.
198
200
        else:
199
201
            self._branch = self.bzrdir.open_branch()
200
202
        self.basedir = realpath(basedir)
201
 
        self._transport = _transport
 
203
        self._control_files = _control_files
 
204
        self._transport = self._control_files._transport
 
205
        # update the whole cache up front and write to disk if anything changed;
 
206
        # in the future we might want to do this more selectively
 
207
        # two possible ways offer themselves : in self._unlock, write the cache
 
208
        # if needed, or, when the cache sees a change, append it to the hash
 
209
        # cache file, and have the parser take the most recent entry for a
 
210
        # given path only.
 
211
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
212
        cache_filename = wt_trans.local_abspath('stat-cache')
 
213
        self._hashcache = hashcache.HashCache(basedir, cache_filename,
 
214
            self.bzrdir._get_file_mode(),
 
215
            self._content_filter_stack_provider())
 
216
        hc = self._hashcache
 
217
        hc.read()
 
218
        # is this scan needed ? it makes things kinda slow.
 
219
        #hc.scan()
 
220
 
 
221
        if hc.needs_write:
 
222
            mutter("write hc")
 
223
            hc.write()
 
224
 
 
225
        self._detect_case_handling()
202
226
        self._rules_searcher = None
203
227
        self.views = self._make_views()
204
228
 
214
238
        """True if filename is the name of a control file in this tree.
215
239
 
216
240
        :param filename: A filename within the tree. This is a relative path
217
 
            from the root of this tree.
 
241
        from the root of this tree.
218
242
 
219
243
        This is true IF and ONLY IF the filename is part of the meta data
220
244
        that bzr controls in this tree. I.E. a random .bzr directory placed
222
246
        """
223
247
        return self.bzrdir.is_control_filename(filename)
224
248
 
 
249
    def _detect_case_handling(self):
 
250
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
251
        try:
 
252
            wt_trans.stat(self._format.case_sensitive_filename)
 
253
        except errors.NoSuchFile:
 
254
            self.case_sensitive = True
 
255
        else:
 
256
            self.case_sensitive = False
 
257
 
 
258
        self._setup_directory_is_tree_reference()
 
259
 
225
260
    branch = property(
226
261
        fget=lambda self: self._branch,
227
262
        doc="""The branch this WorkingTree is connected to.
230
265
            the working tree has been constructed from.
231
266
            """)
232
267
 
233
 
    def has_versioned_directories(self):
234
 
        """See `Tree.has_versioned_directories`."""
235
 
        return self._format.supports_versioned_directories
236
 
 
237
 
    def _supports_executable(self):
238
 
        if sys.platform == 'win32':
239
 
            return False
240
 
        # FIXME: Ideally this should check the file system
241
 
        return True
242
 
 
243
268
    def break_lock(self):
244
269
        """Break a lock if one is present from another instance.
245
270
 
248
273
 
249
274
        This will probe the repository for its lock as well.
250
275
        """
251
 
        raise NotImplementedError(self.break_lock)
 
276
        self._control_files.break_lock()
 
277
        self.branch.break_lock()
 
278
 
 
279
    def _get_check_refs(self):
 
280
        """Return the references needed to perform a check of this tree.
 
281
        
 
282
        The default implementation returns no refs, and is only suitable for
 
283
        trees that have no local caching and can commit on ghosts at any time.
 
284
 
 
285
        :seealso: bzrlib.check for details about check_refs.
 
286
        """
 
287
        return []
252
288
 
253
289
    def requires_rich_root(self):
254
290
        return self._format.requires_rich_root
262
298
    def supports_views(self):
263
299
        return self.views.supports_views()
264
300
 
265
 
    def get_config_stack(self):
266
 
        """Retrieve the config stack for this tree.
267
 
 
268
 
        :return: A ``bzrlib.config.Stack``
269
 
        """
270
 
        # For the moment, just provide the branch config stack.
271
 
        return self.branch.get_config_stack()
272
 
 
273
301
    @staticmethod
274
302
    def open(path=None, _unsupported=False):
275
303
        """Open an existing working tree at path.
277
305
        """
278
306
        if path is None:
279
307
            path = osutils.getcwd()
280
 
        control = controldir.ControlDir.open(path, _unsupported=_unsupported)
281
 
        return control.open_workingtree(unsupported=_unsupported)
 
308
        control = bzrdir.BzrDir.open(path, _unsupported)
 
309
        return control.open_workingtree(_unsupported)
282
310
 
283
311
    @staticmethod
284
312
    def open_containing(path=None):
295
323
        """
296
324
        if path is None:
297
325
            path = osutils.getcwd()
298
 
        control, relpath = controldir.ControlDir.open_containing(path)
 
326
        control, relpath = bzrdir.BzrDir.open_containing(path)
299
327
        return control.open_workingtree(), relpath
300
328
 
301
329
    @staticmethod
321
349
                if view_files:
322
350
                    file_list = view_files
323
351
                    view_str = views.view_display_str(view_files)
324
 
                    note(gettext("Ignoring files outside view. View is %s") % view_str)
 
352
                    note("Ignoring files outside view. View is %s" % view_str)
325
353
            return tree, file_list
326
354
        if default_directory == u'.':
327
355
            seed = file_list[0]
384
412
            else:
385
413
                return True, tree
386
414
        t = transport.get_transport(location)
387
 
        iterator = controldir.ControlDir.find_bzrdirs(t, evaluate=evaluate,
 
415
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
388
416
                                              list_current=list_current)
389
417
        return [tr for tr in iterator if tr is not None]
390
418
 
 
419
    def all_file_ids(self):
 
420
        """See Tree.iter_all_file_ids"""
 
421
        raise NotImplementedError(self.all_file_ids)
 
422
 
391
423
    def __repr__(self):
392
424
        return "<%s of %s>" % (self.__class__.__name__,
393
425
                               getattr(self, 'basedir', None))
482
514
        finally:
483
515
            file.close()
484
516
 
 
517
    def _get_ancestors(self, default_revision):
 
518
        ancestors = set([default_revision])
 
519
        for parent_id in self.get_parent_ids():
 
520
            ancestors.update(self.branch.repository.get_ancestry(
 
521
                             parent_id, topo_sorted=False))
 
522
        return ancestors
 
523
 
485
524
    def get_parent_ids(self):
486
525
        """See Tree.get_parent_ids.
487
526
 
508
547
        raise NotImplementedError(self.get_root_id)
509
548
 
510
549
    @needs_read_lock
511
 
    def clone(self, to_controldir, revision_id=None):
 
550
    def clone(self, to_bzrdir, revision_id=None):
512
551
        """Duplicate this working tree into to_bzr, including all state.
513
552
 
514
553
        Specifically modified files are kept as modified, but
515
554
        ignored and unknown files are discarded.
516
555
 
517
 
        If you want to make a new line of development, see ControlDir.sprout()
 
556
        If you want to make a new line of development, see bzrdir.sprout()
518
557
 
519
558
        revision
520
559
            If not None, the cloned tree will have its last revision set to
522
561
            and this one merged in.
523
562
        """
524
563
        # assumes the target bzr dir format is compatible.
525
 
        result = to_controldir.create_workingtree()
 
564
        result = to_bzrdir.create_workingtree()
526
565
        self.copy_content_into(result, revision_id)
527
566
        return result
528
567
 
535
574
        else:
536
575
            # TODO now merge from tree.last_revision to revision (to preserve
537
576
            # user local changes)
538
 
            try:
539
 
                other_tree = self.revision_tree(revision_id)
540
 
            except errors.NoSuchRevision:
541
 
                other_tree = self.branch.repository.revision_tree(revision_id)
542
 
 
543
 
            merge.transform_tree(tree, other_tree)
544
 
            if revision_id == _mod_revision.NULL_REVISION:
545
 
                new_parents = []
546
 
            else:
547
 
                new_parents = [revision_id]
548
 
            tree.set_parent_ids(new_parents)
 
577
            merge.transform_tree(tree, self)
 
578
            tree.set_parent_ids([revision_id])
549
579
 
550
580
    def id2abspath(self, file_id):
551
581
        return self.abspath(self.id2path(file_id))
552
582
 
553
 
    def _check_for_tree_references(self, iterator):
554
 
        """See if directories have become tree-references."""
555
 
        blocked_parent_ids = set()
556
 
        for path, ie in iterator:
557
 
            if ie.parent_id in blocked_parent_ids:
558
 
                # This entry was pruned because one of its parents became a
559
 
                # TreeReference. If this is a directory, mark it as blocked.
560
 
                if ie.kind == 'directory':
561
 
                    blocked_parent_ids.add(ie.file_id)
562
 
                continue
563
 
            if ie.kind == 'directory' and self._directory_is_tree_reference(path):
564
 
                # This InventoryDirectory needs to be a TreeReference
565
 
                ie = inventory.TreeReference(ie.file_id, ie.name, ie.parent_id)
566
 
                blocked_parent_ids.add(ie.file_id)
567
 
            yield path, ie
568
 
 
569
 
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
570
 
        """See Tree.iter_entries_by_dir()"""
571
 
        # The only trick here is that if we supports_tree_reference then we
572
 
        # need to detect if a directory becomes a tree-reference.
573
 
        iterator = super(WorkingTree, self).iter_entries_by_dir(
574
 
                specific_file_ids=specific_file_ids,
575
 
                yield_parents=yield_parents)
576
 
        if not self.supports_tree_reference():
577
 
            return iterator
578
 
        else:
579
 
            return self._check_for_tree_references(iterator)
580
 
 
581
583
    def get_file_size(self, file_id):
582
584
        """See Tree.get_file_size"""
583
585
        # XXX: this returns the on-disk size; it should probably return the
590
592
            else:
591
593
                return None
592
594
 
 
595
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
596
        # FIXME: Shouldn't this be in Tree?
 
597
        raise NotImplementedError(self.get_file_sha1)
 
598
 
593
599
    @needs_tree_write_lock
594
600
    def _gather_kinds(self, files, kinds):
595
601
        """See MutableTree._gather_kinds."""
610
616
        and setting the list to its value plus revision_id.
611
617
 
612
618
        :param revision_id: The revision id to add to the parent list. It may
613
 
            be a ghost revision as long as its not the first parent to be
614
 
            added, or the allow_leftmost_as_ghost parameter is set True.
 
619
        be a ghost revision as long as its not the first parent to be added,
 
620
        or the allow_leftmost_as_ghost parameter is set True.
615
621
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
616
622
        """
617
623
        parents = self.get_parent_ids() + [revision_id]
752
758
        self._set_merges_from_parent_ids(revision_ids)
753
759
 
754
760
    @needs_tree_write_lock
 
761
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
 
762
        """See MutableTree.set_parent_trees."""
 
763
        parent_ids = [rev for (rev, tree) in parents_list]
 
764
        for revision_id in parent_ids:
 
765
            _mod_revision.check_not_reserved_id(revision_id)
 
766
 
 
767
        self._check_parents_for_ghosts(parent_ids,
 
768
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
 
769
 
 
770
        parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
 
771
 
 
772
        if len(parent_ids) == 0:
 
773
            leftmost_parent_id = _mod_revision.NULL_REVISION
 
774
            leftmost_parent_tree = None
 
775
        else:
 
776
            leftmost_parent_id, leftmost_parent_tree = parents_list[0]
 
777
 
 
778
        if self._change_last_revision(leftmost_parent_id):
 
779
            if leftmost_parent_tree is None:
 
780
                # If we don't have a tree, fall back to reading the
 
781
                # parent tree from the repository.
 
782
                self._cache_basis_inventory(leftmost_parent_id)
 
783
            else:
 
784
                inv = leftmost_parent_tree.inventory
 
785
                xml = self._create_basis_xml_from_inventory(
 
786
                                        leftmost_parent_id, inv)
 
787
                self._write_basis_inventory(xml)
 
788
        self._set_merges_from_parent_ids(parent_ids)
 
789
 
 
790
    @needs_tree_write_lock
755
791
    def set_pending_merges(self, rev_list):
756
792
        parents = self.get_parent_ids()
757
793
        leftmost = parents[:1]
760
796
 
761
797
    @needs_tree_write_lock
762
798
    def set_merge_modified(self, modified_hashes):
763
 
        """Set the merge modified hashes."""
764
 
        raise NotImplementedError(self.set_merge_modified)
 
799
        def iter_stanzas():
 
800
            for file_id, hash in modified_hashes.iteritems():
 
801
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
 
802
                    hash=hash)
 
803
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
765
804
 
766
805
    def _sha_from_stat(self, path, stat_result):
767
806
        """Get a sha digest from the tree's stat cache.
773
812
        """
774
813
        return None
775
814
 
 
815
    def _put_rio(self, filename, stanzas, header):
 
816
        self._must_be_locked()
 
817
        my_file = _mod_rio.rio_file(stanzas, header)
 
818
        self._transport.put_file(filename, my_file,
 
819
            mode=self.bzrdir._get_file_mode())
 
820
 
776
821
    @needs_write_lock # because merge pulls data into the branch.
777
822
    def merge_from_branch(self, branch, to_revision=None, from_revision=None,
778
823
                          merge_type=None, force=False):
838
883
        self.add(path, file_id, 'directory')
839
884
        return file_id
840
885
 
841
 
    def get_symlink_target(self, file_id, path=None):
842
 
        if path is not None:
843
 
            abspath = self.abspath(path)
844
 
        else:
845
 
            abspath = self.id2abspath(file_id)
 
886
    def get_symlink_target(self, file_id):
 
887
        abspath = self.id2abspath(file_id)
846
888
        target = osutils.readlink(abspath)
847
889
        return target
848
890
 
948
990
        file and change the file_id. That is the normal mode. Second, it can
949
991
        only change the file_id without touching any physical file.
950
992
 
951
 
        rename_one uses the second mode if 'after == True' and 'to_rel' is
952
 
        either not versioned or newly added, and present in the working tree.
 
993
        rename_one uses the second mode if 'after == True' and 'to_rel' is not
 
994
        versioned but present in the working tree.
953
995
 
954
996
        rename_one uses the second mode if 'after == False' and 'from_rel' is
955
997
        versioned but no longer in the working tree, and 'to_rel' is not
1000
1042
            new_revision_info = self.branch.last_revision_info()
1001
1043
            if new_revision_info != old_revision_info:
1002
1044
                repository = self.branch.repository
1003
 
                if repository._format.fast_deltas:
1004
 
                    parent_ids = self.get_parent_ids()
1005
 
                    if parent_ids:
1006
 
                        basis_id = parent_ids[0]
1007
 
                        basis_tree = repository.revision_tree(basis_id)
1008
1045
                basis_tree.lock_read()
1009
1046
                try:
1010
1047
                    new_basis_tree = self.branch.basis_tree()
1018
1055
                                show_base=show_base)
1019
1056
                    basis_root_id = basis_tree.get_root_id()
1020
1057
                    new_root_id = new_basis_tree.get_root_id()
1021
 
                    if new_root_id is not None and basis_root_id != new_root_id:
 
1058
                    if basis_root_id != new_root_id:
1022
1059
                        self.set_root_id(new_root_id)
1023
1060
                finally:
1024
1061
                    basis_tree.unlock()
1025
1062
                # TODO - dedup parents list with things merged by pull ?
1026
1063
                # reuse the revisiontree we merged against to set the new
1027
1064
                # tree data.
1028
 
                parent_trees = []
1029
 
                if self.branch.last_revision() != _mod_revision.NULL_REVISION:
1030
 
                    parent_trees.append(
1031
 
                        (self.branch.last_revision(), new_basis_tree))
 
1065
                parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1032
1066
                # we have to pull the merge trees out again, because
1033
1067
                # merge_inner has set the ids. - this corner is not yet
1034
1068
                # layered well enough to prevent double handling.
1051
1085
            stream.write(bytes)
1052
1086
        finally:
1053
1087
            stream.close()
 
1088
        # TODO: update the hashcache here ?
1054
1089
 
1055
1090
    def extras(self):
1056
1091
        """Yield all unversioned files in this WorkingTree.
1133
1168
        else:
1134
1169
            mode = stat_value.st_mode
1135
1170
            kind = osutils.file_kind_from_stat_mode(mode)
1136
 
            if not self._supports_executable():
 
1171
            if not supports_executable():
1137
1172
                executable = entry is not None and entry.executable
1138
1173
            else:
1139
1174
                executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1158
1193
        return _mod_revision.ensure_null(self.branch.last_revision())
1159
1194
 
1160
1195
    def is_locked(self):
1161
 
        """Check if this tree is locked."""
1162
 
        raise NotImplementedError(self.is_locked)
 
1196
        return self._control_files.is_locked()
 
1197
 
 
1198
    def _must_be_locked(self):
 
1199
        if not self.is_locked():
 
1200
            raise errors.ObjectNotLocked(self)
1163
1201
 
1164
1202
    def lock_read(self):
1165
1203
        """Lock the tree for reading.
1168
1206
 
1169
1207
        :return: A bzrlib.lock.LogicalLockResult.
1170
1208
        """
1171
 
        raise NotImplementedError(self.lock_read)
 
1209
        if not self.is_locked():
 
1210
            self._reset_data()
 
1211
        self.branch.lock_read()
 
1212
        try:
 
1213
            self._control_files.lock_read()
 
1214
            return LogicalLockResult(self.unlock)
 
1215
        except:
 
1216
            self.branch.unlock()
 
1217
            raise
1172
1218
 
1173
1219
    def lock_tree_write(self):
1174
1220
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
1175
1221
 
1176
1222
        :return: A bzrlib.lock.LogicalLockResult.
1177
1223
        """
1178
 
        raise NotImplementedError(self.lock_tree_write)
 
1224
        if not self.is_locked():
 
1225
            self._reset_data()
 
1226
        self.branch.lock_read()
 
1227
        try:
 
1228
            self._control_files.lock_write()
 
1229
            return LogicalLockResult(self.unlock)
 
1230
        except:
 
1231
            self.branch.unlock()
 
1232
            raise
1179
1233
 
1180
1234
    def lock_write(self):
1181
1235
        """See MutableTree.lock_write, and WorkingTree.unlock.
1182
1236
 
1183
1237
        :return: A bzrlib.lock.LogicalLockResult.
1184
1238
        """
1185
 
        raise NotImplementedError(self.lock_write)
 
1239
        if not self.is_locked():
 
1240
            self._reset_data()
 
1241
        self.branch.lock_write()
 
1242
        try:
 
1243
            self._control_files.lock_write()
 
1244
            return LogicalLockResult(self.unlock)
 
1245
        except:
 
1246
            self.branch.unlock()
 
1247
            raise
1186
1248
 
1187
1249
    def get_physical_lock_status(self):
1188
 
        raise NotImplementedError(self.get_physical_lock_status)
 
1250
        return self._control_files.get_physical_lock_status()
 
1251
 
 
1252
    def _reset_data(self):
 
1253
        """Reset transient data that cannot be revalidated."""
 
1254
        raise NotImplementedError(self._reset_data)
1189
1255
 
1190
1256
    def set_last_revision(self, new_revision):
1191
1257
        """Change the last revision in the working tree."""
1198
1264
        when their last revision is set.
1199
1265
        """
1200
1266
        if _mod_revision.is_null(new_revision):
1201
 
            self.branch.set_last_revision_info(0, new_revision)
 
1267
            self.branch.set_revision_history([])
1202
1268
            return False
1203
 
        _mod_revision.check_not_reserved_id(new_revision)
1204
1269
        try:
1205
1270
            self.branch.generate_revision_history(new_revision)
1206
1271
        except errors.NoSuchRevision:
1207
1272
            # not present in the repo - dont try to set it deeper than the tip
1208
 
            self.branch._set_revision_history([new_revision])
 
1273
            self.branch.set_revision_history([new_revision])
1209
1274
        return True
1210
1275
 
1211
1276
    @needs_tree_write_lock
1331
1396
    def revert(self, filenames=None, old_tree=None, backups=True,
1332
1397
               pb=None, report_changes=False):
1333
1398
        from bzrlib.conflicts import resolve
 
1399
        if filenames == []:
 
1400
            filenames = None
 
1401
            symbol_versioning.warn('Using [] to revert all files is deprecated'
 
1402
                ' as of bzr 0.91.  Please use None (the default) instead.',
 
1403
                DeprecationWarning, stacklevel=2)
1334
1404
        if old_tree is None:
1335
1405
            basis_tree = self.basis_tree()
1336
1406
            basis_tree.lock_read()
1357
1427
                basis_tree.unlock()
1358
1428
        return conflicts
1359
1429
 
1360
 
    @needs_write_lock
1361
 
    def store_uncommitted(self):
1362
 
        """Store uncommitted changes from the tree in the branch."""
1363
 
        target_tree = self.basis_tree()
1364
 
        shelf_creator = shelf.ShelfCreator(self, target_tree)
1365
 
        try:
1366
 
            if not shelf_creator.shelve_all():
1367
 
                return
1368
 
            self.branch.store_uncommitted(shelf_creator)
1369
 
            shelf_creator.transform()
1370
 
        finally:
1371
 
            shelf_creator.finalize()
1372
 
        note('Uncommitted changes stored in branch "%s".', self.branch.nick)
1373
 
 
1374
 
    @needs_write_lock
1375
 
    def restore_uncommitted(self):
1376
 
        """Restore uncommitted changes from the branch into the tree."""
1377
 
        unshelver = self.branch.get_unshelver(self)
1378
 
        if unshelver is None:
1379
 
            return
1380
 
        try:
1381
 
            merger = unshelver.make_merger()
1382
 
            merger.ignore_zero = True
1383
 
            merger.do_merge()
1384
 
            self.branch.store_uncommitted(None)
1385
 
        finally:
1386
 
            unshelver.finalize()
1387
 
 
1388
1430
    def revision_tree(self, revision_id):
1389
1431
        """See Tree.revision_tree.
1390
1432
 
1447
1489
        - Restore the wt.basis->wt.state changes.
1448
1490
 
1449
1491
        There isn't a single operation at the moment to do that, so we:
1450
 
 
1451
1492
        - Merge current state -> basis tree of the master w.r.t. the old tree
1452
1493
          basis.
1453
1494
        - Do a 'normal' merge of the old branch basis if it is relevant.
1513
1554
                                             show_base=show_base)
1514
1555
            if nb_conflicts:
1515
1556
                self.add_parent_tree((old_tip, other_tree))
1516
 
                note(gettext('Rerun update after fixing the conflicts.'))
 
1557
                note('Rerun update after fixing the conflicts.')
1517
1558
                return nb_conflicts
1518
1559
 
1519
1560
        if last_rev != _mod_revision.ensure_null(revision):
1561
1602
            last_rev = parent_trees[0][0]
1562
1603
        return nb_conflicts
1563
1604
 
 
1605
    def _write_hashcache_if_dirty(self):
 
1606
        """Write out the hashcache if it is dirty."""
 
1607
        if self._hashcache.needs_write:
 
1608
            try:
 
1609
                self._hashcache.write()
 
1610
            except OSError, e:
 
1611
                if e.errno not in (errno.EPERM, errno.EACCES):
 
1612
                    raise
 
1613
                # TODO: jam 20061219 Should this be a warning? A single line
 
1614
                #       warning might be sufficient to let the user know what
 
1615
                #       is going on.
 
1616
                mutter('Could not write hashcache for %s\nError: %s',
 
1617
                              self._hashcache.cache_file_name(), e)
 
1618
 
1564
1619
    def set_conflicts(self, arg):
1565
1620
        raise errors.UnsupportedOperation(self.set_conflicts, self)
1566
1621
 
1694
1749
    def _walkdirs(self, prefix=""):
1695
1750
        """Walk the directories of this tree.
1696
1751
 
1697
 
        :param prefix: is used as the directrory to start with.
1698
 
        :returns: a generator which yields items in the form::
1699
 
 
1700
 
            ((curren_directory_path, fileid),
1701
 
             [(file1_path, file1_name, file1_kind, None, file1_id,
1702
 
               file1_kind), ... ])
 
1752
           :prefix: is used as the directrory to start with.
 
1753
           returns a generator which yields items in the form:
 
1754
                ((curren_directory_path, fileid),
 
1755
                 [(file1_path, file1_name, file1_kind, None, file1_id,
 
1756
                   file1_kind), ... ])
1703
1757
        """
1704
1758
        raise NotImplementedError(self._walkdirs)
1705
1759
 
1711
1765
        are considered 'resolved', because bzr always puts conflict markers
1712
1766
        into files that have text conflicts.  The corresponding .THIS .BASE and
1713
1767
        .OTHER files are deleted, as per 'resolve'.
1714
 
 
1715
1768
        :return: a tuple of ConflictLists: (un_resolved, resolved).
1716
1769
        """
1717
1770
        un_resolved = _mod_conflicts.ConflictList()
1736
1789
        self.set_conflicts(un_resolved)
1737
1790
        return un_resolved, resolved
1738
1791
 
 
1792
    @needs_read_lock
 
1793
    def _check(self, references):
 
1794
        """Check the tree for consistency.
 
1795
 
 
1796
        :param references: A dict with keys matching the items returned by
 
1797
            self._get_check_refs(), and values from looking those keys up in
 
1798
            the repository.
 
1799
        """
 
1800
        tree_basis = self.basis_tree()
 
1801
        tree_basis.lock_read()
 
1802
        try:
 
1803
            repo_basis = references[('trees', self.last_revision())]
 
1804
            if len(list(repo_basis.iter_changes(tree_basis))) > 0:
 
1805
                raise errors.BzrCheckError(
 
1806
                    "Mismatched basis inventory content.")
 
1807
            self._validate()
 
1808
        finally:
 
1809
            tree_basis.unlock()
 
1810
 
1739
1811
    def _validate(self):
1740
1812
        """Validate internal structures.
1741
1813
 
1747
1819
        """
1748
1820
        return
1749
1821
 
 
1822
    @needs_read_lock
1750
1823
    def check_state(self):
1751
1824
        """Check that the working state is/isn't valid."""
1752
 
        raise NotImplementedError(self.check_state)
 
1825
        check_refs = self._get_check_refs()
 
1826
        refs = {}
 
1827
        for ref in check_refs:
 
1828
            kind, value = ref
 
1829
            if kind == 'trees':
 
1830
                refs[ref] = self.branch.repository.revision_tree(value)
 
1831
        self._check(refs)
1753
1832
 
1754
1833
    def reset_state(self, revision_ids=None):
1755
1834
        """Reset the state of the working tree.
1795
1874
        :param branch: A branch to override probing for the branch.
1796
1875
        """
1797
1876
        super(InventoryWorkingTree, self).__init__(basedir=basedir,
1798
 
            branch=branch, _transport=_control_files._transport,
1799
 
            _internal=_internal, _format=_format, _bzrdir=_bzrdir)
1800
 
 
1801
 
        self._control_files = _control_files
1802
 
        self._detect_case_handling()
 
1877
            branch=branch, _control_files=_control_files, _internal=_internal,
 
1878
            _format=_format, _bzrdir=_bzrdir)
1803
1879
 
1804
1880
        if _inventory is None:
1805
1881
            # This will be acquired on lock_read() or lock_write()
1825
1901
        self._inventory = inv
1826
1902
        self._inventory_is_modified = dirty
1827
1903
 
1828
 
    def _detect_case_handling(self):
1829
 
        wt_trans = self.bzrdir.get_workingtree_transport(None)
1830
 
        try:
1831
 
            wt_trans.stat(self._format.case_sensitive_filename)
1832
 
        except errors.NoSuchFile:
1833
 
            self.case_sensitive = True
1834
 
        else:
1835
 
            self.case_sensitive = False
1836
 
 
1837
 
        self._setup_directory_is_tree_reference()
1838
 
 
1839
1904
    def _serialize(self, inventory, out_file):
1840
1905
        xml5.serializer_v5.write_inventory(self._inventory, out_file,
1841
1906
            working=True)
1843
1908
    def _deserialize(selt, in_file):
1844
1909
        return xml5.serializer_v5.read_inventory(in_file)
1845
1910
 
1846
 
    def break_lock(self):
1847
 
        """Break a lock if one is present from another instance.
1848
 
 
1849
 
        Uses the ui factory to ask for confirmation if the lock may be from
1850
 
        an active process.
1851
 
 
1852
 
        This will probe the repository for its lock as well.
1853
 
        """
1854
 
        self._control_files.break_lock()
1855
 
        self.branch.break_lock()
1856
 
 
1857
 
    def is_locked(self):
1858
 
        return self._control_files.is_locked()
1859
 
 
1860
 
    def _must_be_locked(self):
1861
 
        if not self.is_locked():
1862
 
            raise errors.ObjectNotLocked(self)
1863
 
 
1864
 
    def lock_read(self):
1865
 
        """Lock the tree for reading.
1866
 
 
1867
 
        This also locks the branch, and can be unlocked via self.unlock().
1868
 
 
1869
 
        :return: A bzrlib.lock.LogicalLockResult.
1870
 
        """
1871
 
        if not self.is_locked():
1872
 
            self._reset_data()
1873
 
        self.branch.lock_read()
1874
 
        try:
1875
 
            self._control_files.lock_read()
1876
 
            return LogicalLockResult(self.unlock)
1877
 
        except:
1878
 
            self.branch.unlock()
1879
 
            raise
1880
 
 
1881
 
    def lock_tree_write(self):
1882
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
1883
 
 
1884
 
        :return: A bzrlib.lock.LogicalLockResult.
1885
 
        """
1886
 
        if not self.is_locked():
1887
 
            self._reset_data()
1888
 
        self.branch.lock_read()
1889
 
        try:
1890
 
            self._control_files.lock_write()
1891
 
            return LogicalLockResult(self.unlock)
1892
 
        except:
1893
 
            self.branch.unlock()
1894
 
            raise
1895
 
 
1896
 
    def lock_write(self):
1897
 
        """See MutableTree.lock_write, and WorkingTree.unlock.
1898
 
 
1899
 
        :return: A bzrlib.lock.LogicalLockResult.
1900
 
        """
1901
 
        if not self.is_locked():
1902
 
            self._reset_data()
1903
 
        self.branch.lock_write()
1904
 
        try:
1905
 
            self._control_files.lock_write()
1906
 
            return LogicalLockResult(self.unlock)
1907
 
        except:
1908
 
            self.branch.unlock()
1909
 
            raise
1910
 
 
1911
 
    def get_physical_lock_status(self):
1912
 
        return self._control_files.get_physical_lock_status()
1913
 
 
1914
1911
    @needs_tree_write_lock
1915
1912
    def _write_inventory(self, inv):
1916
1913
        """Write inventory as the current inventory."""
1984
1981
            if entry.parent_id == orig_root_id:
1985
1982
                entry.parent_id = inv.root.file_id
1986
1983
 
1987
 
    @needs_tree_write_lock
1988
 
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
1989
 
        """See MutableTree.set_parent_trees."""
1990
 
        parent_ids = [rev for (rev, tree) in parents_list]
1991
 
        for revision_id in parent_ids:
1992
 
            _mod_revision.check_not_reserved_id(revision_id)
1993
 
 
1994
 
        self._check_parents_for_ghosts(parent_ids,
1995
 
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
1996
 
 
1997
 
        parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
1998
 
 
1999
 
        if len(parent_ids) == 0:
2000
 
            leftmost_parent_id = _mod_revision.NULL_REVISION
2001
 
            leftmost_parent_tree = None
2002
 
        else:
2003
 
            leftmost_parent_id, leftmost_parent_tree = parents_list[0]
2004
 
 
2005
 
        if self._change_last_revision(leftmost_parent_id):
2006
 
            if leftmost_parent_tree is None:
2007
 
                # If we don't have a tree, fall back to reading the
2008
 
                # parent tree from the repository.
2009
 
                self._cache_basis_inventory(leftmost_parent_id)
2010
 
            else:
2011
 
                inv = leftmost_parent_tree.root_inventory
2012
 
                xml = self._create_basis_xml_from_inventory(
2013
 
                                        leftmost_parent_id, inv)
2014
 
                self._write_basis_inventory(xml)
2015
 
        self._set_merges_from_parent_ids(parent_ids)
 
1984
    def all_file_ids(self):
 
1985
        """See Tree.iter_all_file_ids"""
 
1986
        return set(self.inventory)
2016
1987
 
2017
1988
    def _cache_basis_inventory(self, new_revision):
2018
1989
        """Cache new_revision as the basis inventory."""
2049
2020
        inventory.revision_id = revision_id
2050
2021
        return xml7.serializer_v7.write_inventory_to_string(inventory)
2051
2022
 
2052
 
    @needs_tree_write_lock
2053
 
    def set_conflicts(self, conflicts):
2054
 
        self._put_rio('conflicts', conflicts.to_stanzas(),
2055
 
                      CONFLICT_HEADER_1)
2056
 
 
2057
 
    @needs_tree_write_lock
2058
 
    def add_conflicts(self, new_conflicts):
2059
 
        conflict_set = set(self.conflicts())
2060
 
        conflict_set.update(set(list(new_conflicts)))
2061
 
        self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
2062
 
                                       key=_mod_conflicts.Conflict.sort_key)))
2063
 
 
2064
 
    @needs_read_lock
2065
 
    def conflicts(self):
2066
 
        try:
2067
 
            confile = self._transport.get('conflicts')
2068
 
        except errors.NoSuchFile:
2069
 
            return _mod_conflicts.ConflictList()
2070
 
        try:
2071
 
            try:
2072
 
                if confile.next() != CONFLICT_HEADER_1 + '\n':
2073
 
                    raise errors.ConflictFormatError()
2074
 
            except StopIteration:
2075
 
                raise errors.ConflictFormatError()
2076
 
            reader = _mod_rio.RioReader(confile)
2077
 
            return _mod_conflicts.ConflictList.from_stanzas(reader)
2078
 
        finally:
2079
 
            confile.close()
2080
 
 
2081
2023
    def read_basis_inventory(self):
2082
2024
        """Read the cached basis inventory."""
2083
2025
        path = self._basis_inventory_name()
2111
2053
 
2112
2054
    def has_id(self, file_id):
2113
2055
        # files that have been deleted are excluded
2114
 
        inv, inv_file_id = self._unpack_file_id(file_id)
2115
 
        if not inv.has_id(inv_file_id):
 
2056
        inv = self.inventory
 
2057
        if not inv.has_id(file_id):
2116
2058
            return False
2117
 
        path = inv.id2path(inv_file_id)
 
2059
        path = inv.id2path(file_id)
2118
2060
        return osutils.lexists(self.abspath(path))
2119
2061
 
2120
2062
    def has_or_had_id(self, file_id):
2121
 
        if file_id == self.get_root_id():
 
2063
        if file_id == self.inventory.root.file_id:
2122
2064
            return True
2123
 
        inv, inv_file_id = self._unpack_file_id(file_id)
2124
 
        return inv.has_id(inv_file_id)
2125
 
 
2126
 
    def all_file_ids(self):
 
2065
        return self.inventory.has_id(file_id)
 
2066
 
 
2067
    __contains__ = has_id
 
2068
 
 
2069
    # should be deprecated - this is slow and in any case treating them as a
 
2070
    # container is (we now know) bad style -- mbp 20070302
 
2071
    ## @deprecated_method(zero_fifteen)
 
2072
    def __iter__(self):
2127
2073
        """Iterate through file_ids for this tree.
2128
2074
 
2129
2075
        file_ids are in a WorkingTree if they are in the working inventory
2130
2076
        and the working file exists.
2131
2077
        """
2132
 
        ret = set()
2133
 
        for path, ie in self.iter_entries_by_dir():
2134
 
            ret.add(ie.file_id)
2135
 
        return ret
 
2078
        inv = self._inventory
 
2079
        for path, ie in inv.iter_entries():
 
2080
            if osutils.lexists(self.abspath(path)):
 
2081
                yield ie.file_id
2136
2082
 
2137
2083
    @needs_tree_write_lock
2138
2084
    def set_last_revision(self, new_revision):
2140
2086
        if self._change_last_revision(new_revision):
2141
2087
            self._cache_basis_inventory(new_revision)
2142
2088
 
2143
 
    def _get_check_refs(self):
2144
 
        """Return the references needed to perform a check of this tree.
2145
 
        
2146
 
        The default implementation returns no refs, and is only suitable for
2147
 
        trees that have no local caching and can commit on ghosts at any time.
2148
 
 
2149
 
        :seealso: bzrlib.check for details about check_refs.
2150
 
        """
2151
 
        return []
2152
 
 
2153
 
    @needs_read_lock
2154
 
    def _check(self, references):
2155
 
        """Check the tree for consistency.
2156
 
 
2157
 
        :param references: A dict with keys matching the items returned by
2158
 
            self._get_check_refs(), and values from looking those keys up in
2159
 
            the repository.
2160
 
        """
2161
 
        tree_basis = self.basis_tree()
2162
 
        tree_basis.lock_read()
2163
 
        try:
2164
 
            repo_basis = references[('trees', self.last_revision())]
2165
 
            if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2166
 
                raise errors.BzrCheckError(
2167
 
                    "Mismatched basis inventory content.")
2168
 
            self._validate()
2169
 
        finally:
2170
 
            tree_basis.unlock()
2171
 
 
2172
 
    @needs_read_lock
2173
 
    def check_state(self):
2174
 
        """Check that the working state is/isn't valid."""
2175
 
        check_refs = self._get_check_refs()
2176
 
        refs = {}
2177
 
        for ref in check_refs:
2178
 
            kind, value = ref
2179
 
            if kind == 'trees':
2180
 
                refs[ref] = self.branch.repository.revision_tree(value)
2181
 
        self._check(refs)
2182
 
 
2183
2089
    @needs_tree_write_lock
2184
2090
    def reset_state(self, revision_ids=None):
2185
2091
        """Reset the state of the working tree.
2194
2100
                _mod_revision.NULL_REVISION)
2195
2101
        else:
2196
2102
            rt = self.branch.repository.revision_tree(revision_ids[0])
2197
 
        self._write_inventory(rt.root_inventory)
 
2103
        self._write_inventory(rt.inventory)
2198
2104
        self.set_parent_ids(revision_ids)
2199
2105
 
2200
2106
    def flush(self):
2209
2115
            mode=self.bzrdir._get_file_mode())
2210
2116
        self._inventory_is_modified = False
2211
2117
 
 
2118
    @needs_read_lock
 
2119
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
2120
        if not path:
 
2121
            path = self._inventory.id2path(file_id)
 
2122
        return self._hashcache.get_sha1(path, stat_value)
 
2123
 
2212
2124
    def get_file_mtime(self, file_id, path=None):
2213
2125
        """See Tree.get_file_mtime."""
2214
2126
        if not path:
2215
 
            path = self.id2path(file_id)
2216
 
        try:
2217
 
            return os.lstat(self.abspath(path)).st_mtime
2218
 
        except OSError, e:
2219
 
            if e.errno == errno.ENOENT:
2220
 
                raise errors.FileTimestampUnavailable(path)
2221
 
            raise
 
2127
            path = self.inventory.id2path(file_id)
 
2128
        return os.lstat(self.abspath(path)).st_mtime
2222
2129
 
2223
2130
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2224
 
        inv, file_id = self._path2inv_file_id(path)
 
2131
        file_id = self.path2id(path)
2225
2132
        if file_id is None:
2226
2133
            # For unversioned files on win32, we just assume they are not
2227
2134
            # executable
2228
2135
            return False
2229
 
        return inv[file_id].executable
 
2136
        return self._inventory[file_id].executable
2230
2137
 
2231
2138
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2232
2139
        mode = stat_result.st_mode
2233
2140
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2234
2141
 
2235
 
    def is_executable(self, file_id, path=None):
2236
 
        if not self._supports_executable():
2237
 
            inv, inv_file_id = self._unpack_file_id(file_id)
2238
 
            return inv[inv_file_id].executable
2239
 
        else:
 
2142
    if not supports_executable():
 
2143
        def is_executable(self, file_id, path=None):
 
2144
            return self._inventory[file_id].executable
 
2145
 
 
2146
        _is_executable_from_path_and_stat = \
 
2147
            _is_executable_from_path_and_stat_from_basis
 
2148
    else:
 
2149
        def is_executable(self, file_id, path=None):
2240
2150
            if not path:
2241
2151
                path = self.id2path(file_id)
2242
2152
            mode = os.lstat(self.abspath(path)).st_mode
2243
2153
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2244
2154
 
2245
 
    def _is_executable_from_path_and_stat(self, path, stat_result):
2246
 
        if not self._supports_executable():
2247
 
            return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
2248
 
        else:
2249
 
            return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
 
2155
        _is_executable_from_path_and_stat = \
 
2156
            _is_executable_from_path_and_stat_from_stat
2250
2157
 
2251
2158
    @needs_tree_write_lock
2252
2159
    def _add(self, files, ids, kinds):
2255
2162
        # should probably put it back with the previous ID.
2256
2163
        # the read and write working inventory should not occur in this
2257
2164
        # function - they should be part of lock_write and unlock.
2258
 
        # FIXME: nested trees
2259
 
        inv = self.root_inventory
 
2165
        inv = self.inventory
2260
2166
        for f, file_id, kind in zip(files, ids, kinds):
2261
2167
            if file_id is None:
2262
2168
                inv.add_path(f, kind=kind)
2303
2209
                parent_tree = self.branch.repository.revision_tree(parent_id)
2304
2210
            parent_tree.lock_read()
2305
2211
            try:
2306
 
                try:
2307
 
                    kind = parent_tree.kind(file_id)
2308
 
                except errors.NoSuchId:
 
2212
                if file_id not in parent_tree:
2309
2213
                    continue
2310
 
                if kind != 'file':
 
2214
                ie = parent_tree.inventory[file_id]
 
2215
                if ie.kind != 'file':
2311
2216
                    # Note: this is slightly unnecessary, because symlinks and
2312
2217
                    # directories have a "text" which is the empty text, and we
2313
2218
                    # know that won't mess up annotations. But it seems cleaner
2314
2219
                    continue
2315
 
                parent_text_key = (
2316
 
                    file_id, parent_tree.get_file_revision(file_id))
 
2220
                parent_text_key = (file_id, ie.revision)
2317
2221
                if parent_text_key not in maybe_file_parent_keys:
2318
2222
                    maybe_file_parent_keys.append(parent_text_key)
2319
2223
            finally:
2334
2238
                       for key, line in annotator.annotate_flat(this_key)]
2335
2239
        return annotations
2336
2240
 
2337
 
    def _put_rio(self, filename, stanzas, header):
2338
 
        self._must_be_locked()
2339
 
        my_file = _mod_rio.rio_file(stanzas, header)
2340
 
        self._transport.put_file(filename, my_file,
2341
 
            mode=self.bzrdir._get_file_mode())
2342
 
 
2343
 
    @needs_tree_write_lock
2344
 
    def set_merge_modified(self, modified_hashes):
2345
 
        def iter_stanzas():
2346
 
            for file_id, hash in modified_hashes.iteritems():
2347
 
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
2348
 
                    hash=hash)
2349
 
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
2350
 
 
2351
2241
    @needs_read_lock
2352
2242
    def merge_modified(self):
2353
2243
        """Return a dictionary of files modified by a merge.
2373
2263
            for s in _mod_rio.RioReader(hashfile):
2374
2264
                # RioReader reads in Unicode, so convert file_ids back to utf8
2375
2265
                file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2376
 
                if not self.has_id(file_id):
 
2266
                if file_id not in self.inventory:
2377
2267
                    continue
2378
2268
                text_hash = s.get("hash")
2379
2269
                if text_hash == self.get_file_sha1(file_id):
2409
2299
        other_tree.lock_tree_write()
2410
2300
        try:
2411
2301
            new_parents = other_tree.get_parent_ids()
2412
 
            other_root = other_tree.root_inventory.root
 
2302
            other_root = other_tree.inventory.root
2413
2303
            other_root.parent_id = new_root_parent
2414
2304
            other_root.name = osutils.basename(other_tree_path)
2415
 
            self.root_inventory.add(other_root)
2416
 
            add_children(self.root_inventory, other_root)
2417
 
            self._write_inventory(self.root_inventory)
 
2305
            self.inventory.add(other_root)
 
2306
            add_children(self.inventory, other_root)
 
2307
            self._write_inventory(self.inventory)
2418
2308
            # normally we don't want to fetch whole repositories, but i think
2419
2309
            # here we really do want to consolidate the whole thing.
2420
2310
            for parent_id in other_tree.get_parent_ids():
2458
2348
        tree_transport = self.bzrdir.root_transport.clone(sub_path)
2459
2349
        if tree_transport.base != branch_transport.base:
2460
2350
            tree_bzrdir = format.initialize_on_transport(tree_transport)
2461
 
            tree_bzrdir.set_branch_reference(new_branch)
 
2351
            branch.BranchReferenceFormat().initialize(tree_bzrdir,
 
2352
                target_branch=new_branch)
2462
2353
        else:
2463
2354
            tree_bzrdir = branch_bzrdir
2464
2355
        wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2465
2356
        wt.set_parent_ids(self.get_parent_ids())
2466
 
        # FIXME: Support nested trees
2467
 
        my_inv = self.root_inventory
 
2357
        my_inv = self.inventory
2468
2358
        child_inv = inventory.Inventory(root_id=None)
2469
2359
        new_root = my_inv[file_id]
2470
2360
        my_inv.remove_recursive_id(file_id)
2490
2380
        if not self.is_locked():
2491
2381
            raise errors.ObjectNotLocked(self)
2492
2382
 
 
2383
        inv = self.inventory
2493
2384
        if from_dir is None and include_root is True:
2494
 
            yield ('', 'V', 'directory', self.get_root_id(), self.root_inventory.root)
 
2385
            yield ('', 'V', 'directory', inv.root.file_id, inv.root)
2495
2386
        # Convert these into local objects to save lookup times
2496
2387
        pathjoin = osutils.pathjoin
2497
2388
        file_kind = self._kind
2504
2395
 
2505
2396
        # directory file_id, relative path, absolute path, reverse sorted children
2506
2397
        if from_dir is not None:
2507
 
            inv, from_dir_id = self._path2inv_file_id(from_dir)
 
2398
            from_dir_id = inv.path2id(from_dir)
2508
2399
            if from_dir_id is None:
2509
2400
                # Directory not versioned
2510
2401
                return
2511
2402
            from_dir_abspath = pathjoin(self.basedir, from_dir)
2512
2403
        else:
2513
 
            inv = self.root_inventory
2514
2404
            from_dir_id = inv.root.file_id
2515
2405
            from_dir_abspath = self.basedir
2516
2406
        children = os.listdir(from_dir_abspath)
2620
2510
        inventory. The second mode only updates the inventory without
2621
2511
        touching the file on the filesystem.
2622
2512
 
2623
 
        move uses the second mode if 'after == True' and the target is
2624
 
        either not versioned or newly added, and present in the working tree.
 
2513
        move uses the second mode if 'after == True' and the target is not
 
2514
        versioned but present in the working tree.
2625
2515
 
2626
2516
        move uses the second mode if 'after == False' and the source is
2627
2517
        versioned but no longer in the working tree, and the target is not
2639
2529
        rename_entries = []
2640
2530
        rename_tuples = []
2641
2531
 
2642
 
        invs_to_write = set()
2643
 
 
2644
2532
        # check for deprecated use of signature
2645
2533
        if to_dir is None:
2646
2534
            raise TypeError('You must supply a target directory')
2647
2535
        # check destination directory
2648
2536
        if isinstance(from_paths, basestring):
2649
2537
            raise ValueError()
 
2538
        inv = self.inventory
2650
2539
        to_abs = self.abspath(to_dir)
2651
2540
        if not isdir(to_abs):
2652
2541
            raise errors.BzrMoveFailedError('',to_dir,
2654
2543
        if not self.has_filename(to_dir):
2655
2544
            raise errors.BzrMoveFailedError('',to_dir,
2656
2545
                errors.NotInWorkingDirectory(to_dir))
2657
 
        to_inv, to_dir_id = self._path2inv_file_id(to_dir)
 
2546
        to_dir_id = inv.path2id(to_dir)
2658
2547
        if to_dir_id is None:
2659
2548
            raise errors.BzrMoveFailedError('',to_dir,
2660
2549
                errors.NotVersionedError(path=to_dir))
2661
2550
 
2662
 
        to_dir_ie = to_inv[to_dir_id]
 
2551
        to_dir_ie = inv[to_dir_id]
2663
2552
        if to_dir_ie.kind != 'directory':
2664
2553
            raise errors.BzrMoveFailedError('',to_dir,
2665
2554
                errors.NotADirectory(to_abs))
2667
2556
        # create rename entries and tuples
2668
2557
        for from_rel in from_paths:
2669
2558
            from_tail = splitpath(from_rel)[-1]
2670
 
            from_inv, from_id = self._path2inv_file_id(from_rel)
 
2559
            from_id = inv.path2id(from_rel)
2671
2560
            if from_id is None:
2672
2561
                raise errors.BzrMoveFailedError(from_rel,to_dir,
2673
2562
                    errors.NotVersionedError(path=from_rel))
2674
2563
 
2675
 
            from_entry = from_inv[from_id]
 
2564
            from_entry = inv[from_id]
2676
2565
            from_parent_id = from_entry.parent_id
2677
2566
            to_rel = pathjoin(to_dir, from_tail)
2678
2567
            rename_entry = InventoryWorkingTree._RenameEntry(
2697
2586
            # restore the inventory on error
2698
2587
            self._inventory_is_modified = original_modified
2699
2588
            raise
2700
 
        #FIXME: Should potentially also write the from_invs
2701
 
        self._write_inventory(to_inv)
 
2589
        self._write_inventory(inv)
2702
2590
        return rename_tuples
2703
2591
 
2704
2592
    @needs_tree_write_lock
2724
2612
 
2725
2613
        Everything else results in an error.
2726
2614
        """
 
2615
        inv = self.inventory
2727
2616
        rename_entries = []
2728
2617
 
2729
2618
        # create rename entries and tuples
2730
2619
        from_tail = splitpath(from_rel)[-1]
2731
 
        from_inv, from_id = self._path2inv_file_id(from_rel)
 
2620
        from_id = inv.path2id(from_rel)
2732
2621
        if from_id is None:
2733
2622
            # if file is missing in the inventory maybe it's in the basis_tree
2734
2623
            basis_tree = self.branch.basis_tree()
2737
2626
                raise errors.BzrRenameFailedError(from_rel,to_rel,
2738
2627
                    errors.NotVersionedError(path=from_rel))
2739
2628
            # put entry back in the inventory so we can rename it
2740
 
            from_entry = basis_tree.root_inventory[from_id].copy()
2741
 
            from_inv.add(from_entry)
 
2629
            from_entry = basis_tree.inventory[from_id].copy()
 
2630
            inv.add(from_entry)
2742
2631
        else:
2743
 
            from_inv, from_inv_id = self._unpack_file_id(from_id)
2744
 
            from_entry = from_inv[from_inv_id]
 
2632
            from_entry = inv[from_id]
2745
2633
        from_parent_id = from_entry.parent_id
2746
2634
        to_dir, to_tail = os.path.split(to_rel)
2747
 
        to_inv, to_dir_id = self._path2inv_file_id(to_dir)
 
2635
        to_dir_id = inv.path2id(to_dir)
2748
2636
        rename_entry = InventoryWorkingTree._RenameEntry(from_rel=from_rel,
2749
2637
                                     from_id=from_id,
2750
2638
                                     from_tail=from_tail,
2772
2660
               from_id, from_rel, to_rel, to_dir, to_dir_id)
2773
2661
 
2774
2662
        self._move(rename_entries)
2775
 
        self._write_inventory(to_inv)
 
2663
        self._write_inventory(inv)
2776
2664
 
2777
2665
    class _RenameEntry(object):
2778
2666
        def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2779
 
                     to_rel, to_tail, to_parent_id, only_change_inv=False,
2780
 
                     change_id=False):
 
2667
                     to_rel, to_tail, to_parent_id, only_change_inv=False):
2781
2668
            self.from_rel = from_rel
2782
2669
            self.from_id = from_id
2783
2670
            self.from_tail = from_tail
2785
2672
            self.to_rel = to_rel
2786
2673
            self.to_tail = to_tail
2787
2674
            self.to_parent_id = to_parent_id
2788
 
            self.change_id = change_id
2789
2675
            self.only_change_inv = only_change_inv
2790
2676
 
2791
2677
    def _determine_mv_mode(self, rename_entries, after=False):
2794
2680
 
2795
2681
        Also does basic plausability tests.
2796
2682
        """
2797
 
        # FIXME: Handling of nested trees
2798
 
        inv = self.root_inventory
 
2683
        inv = self.inventory
2799
2684
 
2800
2685
        for rename_entry in rename_entries:
2801
2686
            # store to local variables for easier reference
2804
2689
            to_rel = rename_entry.to_rel
2805
2690
            to_id = inv.path2id(to_rel)
2806
2691
            only_change_inv = False
2807
 
            change_id = False
2808
2692
 
2809
2693
            # check the inventory for source and destination
2810
2694
            if from_id is None:
2811
2695
                raise errors.BzrMoveFailedError(from_rel,to_rel,
2812
2696
                    errors.NotVersionedError(path=from_rel))
2813
2697
            if to_id is not None:
2814
 
                allowed = False
2815
 
                # allow it with --after but only if dest is newly added
2816
 
                if after:
2817
 
                    basis = self.basis_tree()
2818
 
                    basis.lock_read()
2819
 
                    try:
2820
 
                        if not basis.has_id(to_id):
2821
 
                            rename_entry.change_id = True
2822
 
                            allowed = True
2823
 
                    finally:
2824
 
                        basis.unlock()
2825
 
                if not allowed:
2826
 
                    raise errors.BzrMoveFailedError(from_rel,to_rel,
2827
 
                        errors.AlreadyVersionedError(path=to_rel))
 
2698
                raise errors.BzrMoveFailedError(from_rel,to_rel,
 
2699
                    errors.AlreadyVersionedError(path=to_rel))
2828
2700
 
2829
2701
            # try to determine the mode for rename (only change inv or change
2830
2702
            # inv and file system)
2846
2718
                # something is wrong, so lets determine what exactly
2847
2719
                if not self.has_filename(from_rel) and \
2848
2720
                   not self.has_filename(to_rel):
2849
 
                    raise errors.BzrRenameFailedError(from_rel, to_rel,
2850
 
                        errors.PathsDoNotExist(paths=(from_rel, to_rel)))
 
2721
                    raise errors.BzrRenameFailedError(from_rel,to_rel,
 
2722
                        errors.PathsDoNotExist(paths=(str(from_rel),
 
2723
                        str(to_rel))))
2851
2724
                else:
2852
2725
                    raise errors.RenameFailedFilesExist(from_rel, to_rel)
2853
2726
            rename_entry.only_change_inv = only_change_inv
2859
2732
        Depending on the value of the flag 'only_change_inv', the
2860
2733
        file will be moved on the file system or not.
2861
2734
        """
 
2735
        inv = self.inventory
2862
2736
        moved = []
2863
2737
 
2864
2738
        for entry in rename_entries:
2871
2745
 
2872
2746
    def _rollback_move(self, moved):
2873
2747
        """Try to rollback a previous move in case of an filesystem error."""
 
2748
        inv = self.inventory
2874
2749
        for entry in moved:
2875
2750
            try:
2876
2751
                self._move_entry(WorkingTree._RenameEntry(
2885
2760
                        " Error message is: %s" % e)
2886
2761
 
2887
2762
    def _move_entry(self, entry):
2888
 
        inv = self.root_inventory
 
2763
        inv = self.inventory
2889
2764
        from_rel_abs = self.abspath(entry.from_rel)
2890
2765
        to_rel_abs = self.abspath(entry.to_rel)
2891
2766
        if from_rel_abs == to_rel_abs:
2898
2773
            except OSError, e:
2899
2774
                raise errors.BzrMoveFailedError(entry.from_rel,
2900
2775
                    entry.to_rel, e[1])
2901
 
        if entry.change_id:
2902
 
            to_id = inv.path2id(entry.to_rel)
2903
 
            inv.remove_recursive_id(to_id)
2904
2776
        inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
2905
2777
 
2906
2778
    @needs_tree_write_lock
2914
2786
        :raises: NoSuchId if any fileid is not currently versioned.
2915
2787
        """
2916
2788
        for file_id in file_ids:
2917
 
            if not self._inventory.has_id(file_id):
 
2789
            if file_id not in self._inventory:
2918
2790
                raise errors.NoSuchId(self, file_id)
2919
2791
        for file_id in file_ids:
2920
2792
            if self._inventory.has_id(file_id):
2932
2804
 
2933
2805
    def stored_kind(self, file_id):
2934
2806
        """See Tree.stored_kind"""
2935
 
        inv, inv_file_id = self._unpack_file_id(file_id)
2936
 
        return inv[inv_file_id].kind
 
2807
        return self.inventory[file_id].kind
2937
2808
 
2938
2809
    def extras(self):
2939
2810
        """Yield all unversioned files in this WorkingTree.
2946
2817
        This is the same order used by 'osutils.walkdirs'.
2947
2818
        """
2948
2819
        ## TODO: Work from given directory downwards
2949
 
        for path, dir_entry in self.iter_entries_by_dir():
2950
 
            if dir_entry.kind != 'directory':
2951
 
                continue
 
2820
        for path, dir_entry in self.inventory.directories():
2952
2821
            # mutter("search for unknowns in %r", path)
2953
2822
            dirabs = self.abspath(path)
2954
2823
            if not isdir(dirabs):
2982
2851
    def _walkdirs(self, prefix=""):
2983
2852
        """Walk the directories of this tree.
2984
2853
 
2985
 
        :param prefix: is used as the directrory to start with.
2986
 
        :returns: a generator which yields items in the form::
2987
 
 
2988
 
            ((curren_directory_path, fileid),
2989
 
             [(file1_path, file1_name, file1_kind, None, file1_id,
2990
 
               file1_kind), ... ])
 
2854
           :prefix: is used as the directrory to start with.
 
2855
           returns a generator which yields items in the form:
 
2856
                ((curren_directory_path, fileid),
 
2857
                 [(file1_path, file1_name, file1_kind, None, file1_id,
 
2858
                   file1_kind), ... ])
2991
2859
        """
2992
2860
        _directory = 'directory'
2993
2861
        # get the root in the inventory
2994
 
        inv, top_id = self._path2inv_file_id(prefix)
 
2862
        inv = self.inventory
 
2863
        top_id = inv.path2id(prefix)
2995
2864
        if top_id is None:
2996
2865
            pending = []
2997
2866
        else:
3018
2887
                if dir[2] == _directory:
3019
2888
                    pending.append(dir)
3020
2889
 
3021
 
    @needs_write_lock
3022
 
    def update_feature_flags(self, updated_flags):
3023
 
        """Update the feature flags for this branch.
3024
 
 
3025
 
        :param updated_flags: Dictionary mapping feature names to necessities
3026
 
            A necessity can be None to indicate the feature should be removed
3027
 
        """
3028
 
        self._format._update_feature_flags(updated_flags)
3029
 
        self.control_transport.put_bytes('format', self._format.as_string())
 
2890
 
 
2891
class WorkingTree3(InventoryWorkingTree):
 
2892
    """This is the Format 3 working tree.
 
2893
 
 
2894
    This differs from the base WorkingTree by:
 
2895
     - having its own file lock
 
2896
     - having its own last-revision property.
 
2897
 
 
2898
    This is new in bzr 0.8
 
2899
    """
 
2900
 
 
2901
    @needs_read_lock
 
2902
    def _last_revision(self):
 
2903
        """See Mutable.last_revision."""
 
2904
        try:
 
2905
            return self._transport.get_bytes('last-revision')
 
2906
        except errors.NoSuchFile:
 
2907
            return _mod_revision.NULL_REVISION
 
2908
 
 
2909
    def _change_last_revision(self, revision_id):
 
2910
        """See WorkingTree._change_last_revision."""
 
2911
        if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
 
2912
            try:
 
2913
                self._transport.delete('last-revision')
 
2914
            except errors.NoSuchFile:
 
2915
                pass
 
2916
            return False
 
2917
        else:
 
2918
            self._transport.put_bytes('last-revision', revision_id,
 
2919
                mode=self.bzrdir._get_file_mode())
 
2920
            return True
 
2921
 
 
2922
    def _get_check_refs(self):
 
2923
        """Return the references needed to perform a check of this tree."""
 
2924
        return [('trees', self.last_revision())]
 
2925
 
 
2926
    @needs_tree_write_lock
 
2927
    def set_conflicts(self, conflicts):
 
2928
        self._put_rio('conflicts', conflicts.to_stanzas(),
 
2929
                      CONFLICT_HEADER_1)
 
2930
 
 
2931
    @needs_tree_write_lock
 
2932
    def add_conflicts(self, new_conflicts):
 
2933
        conflict_set = set(self.conflicts())
 
2934
        conflict_set.update(set(list(new_conflicts)))
 
2935
        self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
 
2936
                                       key=_mod_conflicts.Conflict.sort_key)))
 
2937
 
 
2938
    @needs_read_lock
 
2939
    def conflicts(self):
 
2940
        try:
 
2941
            confile = self._transport.get('conflicts')
 
2942
        except errors.NoSuchFile:
 
2943
            return _mod_conflicts.ConflictList()
 
2944
        try:
 
2945
            try:
 
2946
                if confile.next() != CONFLICT_HEADER_1 + '\n':
 
2947
                    raise errors.ConflictFormatError()
 
2948
            except StopIteration:
 
2949
                raise errors.ConflictFormatError()
 
2950
            reader = _mod_rio.RioReader(confile)
 
2951
            return _mod_conflicts.ConflictList.from_stanzas(reader)
 
2952
        finally:
 
2953
            confile.close()
 
2954
 
 
2955
    def unlock(self):
 
2956
        # do non-implementation specific cleanup
 
2957
        self._cleanup()
 
2958
        if self._control_files._lock_count == 1:
 
2959
            # _inventory_is_modified is always False during a read lock.
 
2960
            if self._inventory_is_modified:
 
2961
                self.flush()
 
2962
            self._write_hashcache_if_dirty()
 
2963
        # reverse order of locking.
 
2964
        try:
 
2965
            return self._control_files.unlock()
 
2966
        finally:
 
2967
            self.branch.unlock()
3030
2968
 
3031
2969
 
3032
2970
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
3035
2973
    def __init__(self, other_registry=None):
3036
2974
        super(WorkingTreeFormatRegistry, self).__init__(other_registry)
3037
2975
        self._default_format = None
3038
 
        self._default_format_key = None
3039
2976
 
3040
2977
    def get_default(self):
3041
2978
        """Return the current default format."""
3042
 
        if (self._default_format_key is not None and
3043
 
            self._default_format is None):
3044
 
            self._default_format = self.get(self._default_format_key)
3045
2979
        return self._default_format
3046
2980
 
3047
2981
    def set_default(self, format):
3048
 
        """Set the default format."""
3049
2982
        self._default_format = format
3050
 
        self._default_format_key = None
3051
 
 
3052
 
    def set_default_key(self, format_string):
3053
 
        """Set the default format by its format string."""
3054
 
        self._default_format_key = format_string
3055
 
        self._default_format = None
3056
2983
 
3057
2984
 
3058
2985
format_registry = WorkingTreeFormatRegistry()
3087
3014
    missing_parent_conflicts = False
3088
3015
    """If this format supports missing parent conflicts."""
3089
3016
 
3090
 
    supports_versioned_directories = None
 
3017
    @classmethod
 
3018
    def find_format(klass, a_bzrdir):
 
3019
        """Return the format for the working tree object in a_bzrdir."""
 
3020
        try:
 
3021
            transport = a_bzrdir.get_workingtree_transport(None)
 
3022
            format_string = transport.get_bytes("format")
 
3023
            return format_registry.get(format_string)
 
3024
        except errors.NoSuchFile:
 
3025
            raise errors.NoWorkingTree(base=transport.base)
 
3026
        except KeyError:
 
3027
            raise errors.UnknownFormatError(format=format_string,
 
3028
                                            kind="working tree")
3091
3029
 
3092
 
    def initialize(self, controldir, revision_id=None, from_branch=None,
 
3030
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3093
3031
                   accelerator_tree=None, hardlink=False):
3094
 
        """Initialize a new working tree in controldir.
 
3032
        """Initialize a new working tree in a_bzrdir.
3095
3033
 
3096
 
        :param controldir: ControlDir to initialize the working tree in.
 
3034
        :param a_bzrdir: BzrDir to initialize the working tree in.
3097
3035
        :param revision_id: allows creating a working tree at a different
3098
3036
            revision than the branch is at.
3099
3037
        :param from_branch: Branch to checkout
3112
3050
    def __ne__(self, other):
3113
3051
        return not (self == other)
3114
3052
 
 
3053
    @classmethod
 
3054
    @symbol_versioning.deprecated_method(
 
3055
        symbol_versioning.deprecated_in((2, 4, 0)))
 
3056
    def get_default_format(klass):
 
3057
        """Return the current default format."""
 
3058
        return format_registry.get_default()
 
3059
 
 
3060
    def get_format_string(self):
 
3061
        """Return the ASCII format string that identifies this format."""
 
3062
        raise NotImplementedError(self.get_format_string)
 
3063
 
3115
3064
    def get_format_description(self):
3116
3065
        """Return the short description for this format."""
3117
3066
        raise NotImplementedError(self.get_format_description)
3133
3082
        """True if this format supports stored views."""
3134
3083
        return False
3135
3084
 
3136
 
    def get_controldir_for_branch(self):
3137
 
        """Get the control directory format for creating branches.
3138
 
 
3139
 
        This is to support testing of working tree formats that can not exist
3140
 
        in the same control directory as a branch.
3141
 
        """
3142
 
        return self._matchingbzrdir
3143
 
 
3144
 
 
3145
 
class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
3146
 
    """Base class for working trees that live in bzr meta directories."""
3147
 
 
3148
 
    def __init__(self):
3149
 
        WorkingTreeFormat.__init__(self)
3150
 
        bzrdir.BzrFormat.__init__(self)
3151
 
 
3152
 
    @classmethod
3153
 
    def find_format_string(klass, controldir):
3154
 
        """Return format name for the working tree object in controldir."""
3155
 
        try:
3156
 
            transport = controldir.get_workingtree_transport(None)
3157
 
            return transport.get_bytes("format")
3158
 
        except errors.NoSuchFile:
3159
 
            raise errors.NoWorkingTree(base=transport.base)
3160
 
 
3161
 
    @classmethod
3162
 
    def find_format(klass, controldir):
3163
 
        """Return the format for the working tree object in controldir."""
3164
 
        format_string = klass.find_format_string(controldir)
3165
 
        return klass._find_format(format_registry, 'working tree',
3166
 
                format_string)
3167
 
 
3168
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
3169
 
            basedir=None):
3170
 
        WorkingTreeFormat.check_support_status(self,
3171
 
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
3172
 
            basedir=basedir)
3173
 
        bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
3174
 
            recommend_upgrade=recommend_upgrade, basedir=basedir)
3175
 
 
3176
 
    def get_controldir_for_branch(self):
3177
 
        """Get the control directory format for creating branches.
3178
 
 
3179
 
        This is to support testing of working tree formats that can not exist
3180
 
        in the same control directory as a branch.
3181
 
        """
3182
 
        return self._matchingbzrdir
3183
 
 
3184
 
 
3185
 
class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
3186
 
    """Base class for working trees that live in bzr meta directories."""
3187
 
 
3188
 
    def __init__(self):
3189
 
        WorkingTreeFormat.__init__(self)
3190
 
        bzrdir.BzrFormat.__init__(self)
3191
 
 
3192
 
    @classmethod
3193
 
    def find_format_string(klass, controldir):
3194
 
        """Return format name for the working tree object in controldir."""
3195
 
        try:
3196
 
            transport = controldir.get_workingtree_transport(None)
3197
 
            return transport.get_bytes("format")
3198
 
        except errors.NoSuchFile:
3199
 
            raise errors.NoWorkingTree(base=transport.base)
3200
 
 
3201
 
    @classmethod
3202
 
    def find_format(klass, controldir):
3203
 
        """Return the format for the working tree object in controldir."""
3204
 
        format_string = klass.find_format_string(controldir)
3205
 
        return klass._find_format(format_registry, 'working tree',
3206
 
                format_string)
3207
 
 
3208
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
3209
 
            basedir=None):
3210
 
        WorkingTreeFormat.check_support_status(self,
3211
 
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
3212
 
            basedir=basedir)
3213
 
        bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
3214
 
            recommend_upgrade=recommend_upgrade, basedir=basedir)
3215
 
 
3216
 
 
 
3085
    @classmethod
 
3086
    @symbol_versioning.deprecated_method(
 
3087
        symbol_versioning.deprecated_in((2, 4, 0)))
 
3088
    def register_format(klass, format):
 
3089
        format_registry.register(format)
 
3090
 
 
3091
    @classmethod
 
3092
    @symbol_versioning.deprecated_method(
 
3093
        symbol_versioning.deprecated_in((2, 4, 0)))
 
3094
    def register_extra_format(klass, format):
 
3095
        format_registry.register_extra(format)
 
3096
 
 
3097
    @classmethod
 
3098
    @symbol_versioning.deprecated_method(
 
3099
        symbol_versioning.deprecated_in((2, 4, 0)))
 
3100
    def unregister_extra_format(klass, format):
 
3101
        format_registry.unregister_extra(format)
 
3102
 
 
3103
    @classmethod
 
3104
    @symbol_versioning.deprecated_method(
 
3105
        symbol_versioning.deprecated_in((2, 4, 0)))
 
3106
    def get_formats(klass):
 
3107
        return format_registry._get_all()
 
3108
 
 
3109
    @classmethod
 
3110
    @symbol_versioning.deprecated_method(
 
3111
        symbol_versioning.deprecated_in((2, 4, 0)))
 
3112
    def set_default_format(klass, format):
 
3113
        format_registry.set_default(format)
 
3114
 
 
3115
    @classmethod
 
3116
    @symbol_versioning.deprecated_method(
 
3117
        symbol_versioning.deprecated_in((2, 4, 0)))
 
3118
    def unregister_format(klass, format):
 
3119
        format_registry.remove(format)
 
3120
 
 
3121
 
 
3122
class WorkingTreeFormat3(WorkingTreeFormat):
 
3123
    """The second working tree format updated to record a format marker.
 
3124
 
 
3125
    This format:
 
3126
        - exists within a metadir controlling .bzr
 
3127
        - includes an explicit version marker for the workingtree control
 
3128
          files, separate from the BzrDir format
 
3129
        - modifies the hash cache format
 
3130
        - is new in bzr 0.8
 
3131
        - uses a LockDir to guard access for writes.
 
3132
    """
 
3133
 
 
3134
    upgrade_recommended = True
 
3135
 
 
3136
    missing_parent_conflicts = True
 
3137
 
 
3138
    def get_format_string(self):
 
3139
        """See WorkingTreeFormat.get_format_string()."""
 
3140
        return "Bazaar-NG Working Tree format 3"
 
3141
 
 
3142
    def get_format_description(self):
 
3143
        """See WorkingTreeFormat.get_format_description()."""
 
3144
        return "Working tree format 3"
 
3145
 
 
3146
    _lock_file_name = 'lock'
 
3147
    _lock_class = LockDir
 
3148
 
 
3149
    _tree_class = WorkingTree3
 
3150
 
 
3151
    def __get_matchingbzrdir(self):
 
3152
        return bzrdir.BzrDirMetaFormat1()
 
3153
 
 
3154
    _matchingbzrdir = property(__get_matchingbzrdir)
 
3155
 
 
3156
    def _open_control_files(self, a_bzrdir):
 
3157
        transport = a_bzrdir.get_workingtree_transport(None)
 
3158
        return LockableFiles(transport, self._lock_file_name,
 
3159
                             self._lock_class)
 
3160
 
 
3161
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
3162
                   accelerator_tree=None, hardlink=False):
 
3163
        """See WorkingTreeFormat.initialize().
 
3164
 
 
3165
        :param revision_id: if supplied, create a working tree at a different
 
3166
            revision than the branch is at.
 
3167
        :param accelerator_tree: A tree which can be used for retrieving file
 
3168
            contents more quickly than the revision tree, i.e. a workingtree.
 
3169
            The revision tree will be used for cases where accelerator_tree's
 
3170
            content is different.
 
3171
        :param hardlink: If true, hard-link files from accelerator_tree,
 
3172
            where possible.
 
3173
        """
 
3174
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
3175
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
3176
        transport = a_bzrdir.get_workingtree_transport(self)
 
3177
        control_files = self._open_control_files(a_bzrdir)
 
3178
        control_files.create_lock()
 
3179
        control_files.lock_write()
 
3180
        transport.put_bytes('format', self.get_format_string(),
 
3181
            mode=a_bzrdir._get_file_mode())
 
3182
        if from_branch is not None:
 
3183
            branch = from_branch
 
3184
        else:
 
3185
            branch = a_bzrdir.open_branch()
 
3186
        if revision_id is None:
 
3187
            revision_id = _mod_revision.ensure_null(branch.last_revision())
 
3188
        # WorkingTree3 can handle an inventory which has a unique root id.
 
3189
        # as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
 
3190
        # those trees. And because there isn't a format bump inbetween, we
 
3191
        # are maintaining compatibility with older clients.
 
3192
        # inv = Inventory(root_id=gen_root_id())
 
3193
        inv = self._initial_inventory()
 
3194
        wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
 
3195
                         branch,
 
3196
                         inv,
 
3197
                         _internal=True,
 
3198
                         _format=self,
 
3199
                         _bzrdir=a_bzrdir,
 
3200
                         _control_files=control_files)
 
3201
        wt.lock_tree_write()
 
3202
        try:
 
3203
            basis_tree = branch.repository.revision_tree(revision_id)
 
3204
            # only set an explicit root id if there is one to set.
 
3205
            if basis_tree.inventory.root is not None:
 
3206
                wt.set_root_id(basis_tree.get_root_id())
 
3207
            if revision_id == _mod_revision.NULL_REVISION:
 
3208
                wt.set_parent_trees([])
 
3209
            else:
 
3210
                wt.set_parent_trees([(revision_id, basis_tree)])
 
3211
            transform.build_tree(basis_tree, wt)
 
3212
        finally:
 
3213
            # Unlock in this order so that the unlock-triggers-flush in
 
3214
            # WorkingTree is given a chance to fire.
 
3215
            control_files.unlock()
 
3216
            wt.unlock()
 
3217
        return wt
 
3218
 
 
3219
    def _initial_inventory(self):
 
3220
        return inventory.Inventory()
 
3221
 
 
3222
    def __init__(self):
 
3223
        super(WorkingTreeFormat3, self).__init__()
 
3224
 
 
3225
    def open(self, a_bzrdir, _found=False):
 
3226
        """Return the WorkingTree object for a_bzrdir
 
3227
 
 
3228
        _found is a private parameter, do not use it. It is used to indicate
 
3229
               if format probing has already been done.
 
3230
        """
 
3231
        if not _found:
 
3232
            # we are being called directly and must probe.
 
3233
            raise NotImplementedError
 
3234
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
3235
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
3236
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
 
3237
        return wt
 
3238
 
 
3239
    def _open(self, a_bzrdir, control_files):
 
3240
        """Open the tree itself.
 
3241
 
 
3242
        :param a_bzrdir: the dir for the tree.
 
3243
        :param control_files: the control files for the tree.
 
3244
        """
 
3245
        return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
 
3246
                                _internal=True,
 
3247
                                _format=self,
 
3248
                                _bzrdir=a_bzrdir,
 
3249
                                _control_files=control_files)
 
3250
 
 
3251
    def __str__(self):
 
3252
        return self.get_format_string()
 
3253
 
 
3254
 
 
3255
__default_format = WorkingTreeFormat6()
3217
3256
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3218
3257
    "bzrlib.workingtree_4", "WorkingTreeFormat4")
3219
3258
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3220
3259
    "bzrlib.workingtree_4", "WorkingTreeFormat5")
3221
3260
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3222
3261
    "bzrlib.workingtree_4", "WorkingTreeFormat6")
3223
 
format_registry.register_lazy("Bazaar-NG Working Tree format 3",
3224
 
    "bzrlib.workingtree_3", "WorkingTreeFormat3")
3225
 
format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")
 
3262
format_registry.register(WorkingTreeFormat3())
 
3263
format_registry.set_default(__default_format)