~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

Merge bzr.dev and tree-file-ids-as-tuples.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2007-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""WorkingTree4 format and implementation.
18
18
 
22
22
WorkingTree.open(dir).
23
23
"""
24
24
 
 
25
from __future__ import absolute_import
 
26
 
25
27
from cStringIO import StringIO
26
28
import os
27
29
import sys
28
30
 
29
31
from bzrlib.lazy_import import lazy_import
30
32
lazy_import(globals(), """
31
 
from bisect import bisect_left
32
 
import collections
33
 
from copy import deepcopy
34
33
import errno
35
 
import itertools
36
 
import operator
37
34
import stat
38
 
from time import time
39
 
import warnings
40
35
 
41
 
import bzrlib
42
36
from bzrlib import (
43
37
    bzrdir,
44
38
    cache_utf8,
 
39
    config,
45
40
    conflicts as _mod_conflicts,
46
41
    debug,
47
 
    delta,
48
42
    dirstate,
49
43
    errors,
 
44
    filters as _mod_filters,
50
45
    generate_ids,
51
 
    globbing,
52
 
    ignores,
53
 
    merge,
54
46
    osutils,
55
47
    revision as _mod_revision,
56
48
    revisiontree,
57
 
    textui,
58
49
    trace,
59
50
    transform,
60
 
    urlutils,
61
 
    xml5,
62
 
    xml6,
 
51
    views,
63
52
    )
64
 
import bzrlib.branch
65
 
from bzrlib.transport import get_transport
66
 
import bzrlib.ui
67
53
""")
68
54
 
69
 
from bzrlib import symbol_versioning
70
55
from bzrlib.decorators import needs_read_lock, needs_write_lock
71
 
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
72
 
from bzrlib.lockable_files import LockableFiles, TransportLock
 
56
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
 
57
from bzrlib.lock import LogicalLockResult
 
58
from bzrlib.lockable_files import LockableFiles
73
59
from bzrlib.lockdir import LockDir
74
 
import bzrlib.mutabletree
75
 
from bzrlib.mutabletree import needs_tree_write_lock
 
60
from bzrlib.mutabletree import (
 
61
    MutableTree,
 
62
    needs_tree_write_lock,
 
63
    )
76
64
from bzrlib.osutils import (
77
65
    file_kind,
78
66
    isdir,
79
 
    normpath,
80
67
    pathjoin,
81
 
    rand_chars,
82
68
    realpath,
83
69
    safe_unicode,
84
 
    splitpath,
85
 
    )
86
 
from bzrlib.trace import mutter, note
 
70
    )
 
71
from bzrlib.symbol_versioning import (
 
72
    deprecated_in,
 
73
    deprecated_method,
 
74
    )
87
75
from bzrlib.transport.local import LocalTransport
88
 
from bzrlib.tree import InterTree
89
 
from bzrlib.progress import DummyProgress, ProgressPhase
90
 
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
91
 
from bzrlib.rio import RioReader, rio_file, Stanza
92
 
from bzrlib.symbol_versioning import (deprecated_passed,
93
 
        deprecated_method,
94
 
        deprecated_function,
95
 
        DEPRECATED_PARAMETER,
96
 
        )
97
 
from bzrlib.tree import Tree
98
 
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
99
 
 
100
 
 
101
 
class WorkingTree4(WorkingTree3):
102
 
    """This is the Format 4 working tree.
103
 
 
104
 
    This differs from WorkingTree3 by:
105
 
     - Having a consolidated internal dirstate, stored in a
106
 
       randomly-accessible sorted file on disk.
107
 
     - Not having a regular inventory attribute.  One can be synthesized 
108
 
       on demand but this is expensive and should be avoided.
109
 
 
110
 
    This is new in bzr 0.15.
111
 
    """
 
76
from bzrlib.tree import (
 
77
    InterTree,
 
78
    InventoryTree,
 
79
    )
 
80
from bzrlib.workingtree import (
 
81
    InventoryWorkingTree,
 
82
    WorkingTree,
 
83
    WorkingTreeFormatMetaDir,
 
84
    )
 
85
 
 
86
 
 
87
class DirStateWorkingTree(InventoryWorkingTree):
112
88
 
113
89
    def __init__(self, basedir,
114
90
                 branch,
125
101
        self._format = _format
126
102
        self.bzrdir = _bzrdir
127
103
        basedir = safe_unicode(basedir)
128
 
        mutter("opening working tree %r", basedir)
 
104
        trace.mutter("opening working tree %r", basedir)
129
105
        self._branch = branch
130
106
        self.basedir = realpath(basedir)
131
107
        # if branch is at our basedir and is a format 6 or less
142
118
        self._setup_directory_is_tree_reference()
143
119
        self._detect_case_handling()
144
120
        self._rules_searcher = None
 
121
        self.views = self._make_views()
145
122
        #--- allow tests to select the dirstate iter_changes implementation
146
123
        self._iter_changes = dirstate._process_entry
147
124
 
164
141
            state.add(f, file_id, kind, None, '')
165
142
        self._make_dirty(reset_inventory=True)
166
143
 
 
144
    def _get_check_refs(self):
 
145
        """Return the references needed to perform a check of this tree."""
 
146
        return [('trees', self.last_revision())]
 
147
 
167
148
    def _make_dirty(self, reset_inventory):
168
149
        """Make the tree state dirty.
169
150
 
177
158
    @needs_tree_write_lock
178
159
    def add_reference(self, sub_tree):
179
160
        # use standard implementation, which calls back to self._add
180
 
        # 
 
161
        #
181
162
        # So we don't store the reference_revision in the working dirstate,
182
 
        # it's just recorded at the moment of commit. 
 
163
        # it's just recorded at the moment of commit.
183
164
        self._add_reference(sub_tree)
184
165
 
185
166
    def break_lock(self):
221
202
 
222
203
    def _comparison_data(self, entry, path):
223
204
        kind, executable, stat_value = \
224
 
            WorkingTree3._comparison_data(self, entry, path)
 
205
            WorkingTree._comparison_data(self, entry, path)
225
206
        # it looks like a plain directory, but it's really a reference -- see
226
207
        # also kind()
227
 
        if (self._repo_supports_tree_reference and
228
 
            kind == 'directory' and
229
 
            self._directory_is_tree_reference(path)):
 
208
        if (self._repo_supports_tree_reference and kind == 'directory'
 
209
            and entry is not None and entry.kind == 'tree-reference'):
230
210
            kind = 'tree-reference'
231
211
        return kind, executable, stat_value
232
212
 
234
214
    def commit(self, message=None, revprops=None, *args, **kwargs):
235
215
        # mark the tree as dirty post commit - commit
236
216
        # can change the current versioned list by doing deletes.
237
 
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
 
217
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
238
218
        self._make_dirty(reset_inventory=True)
239
219
        return result
240
220
 
258
238
            return self._dirstate
259
239
        local_path = self.bzrdir.get_workingtree_transport(None
260
240
            ).local_abspath('dirstate')
261
 
        self._dirstate = dirstate.DirState.on_file(local_path)
 
241
        self._dirstate = dirstate.DirState.on_file(local_path,
 
242
            self._sha1_provider(), self._worth_saving_limit())
262
243
        return self._dirstate
263
244
 
 
245
    def _sha1_provider(self):
 
246
        """A function that returns a SHA1Provider suitable for this tree.
 
247
 
 
248
        :return: None if content filtering is not supported by this tree.
 
249
          Otherwise, a SHA1Provider is returned that sha's the canonical
 
250
          form of files, i.e. after read filters are applied.
 
251
        """
 
252
        if self.supports_content_filtering():
 
253
            return ContentFilterAwareSHA1Provider(self)
 
254
        else:
 
255
            return None
 
256
 
 
257
    def _worth_saving_limit(self):
 
258
        """How many hash changes are ok before we must save the dirstate.
 
259
 
 
260
        :return: an integer. -1 means never save.
 
261
        """
 
262
        # FIXME: We want a WorkingTreeStack here -- vila 20110812
 
263
        conf = config.BranchStack(self.branch)
 
264
        return conf.get('bzr.workingtree.worth_saving_limit')
 
265
 
264
266
    def filter_unversioned_files(self, paths):
265
267
        """Filter out paths that are versioned.
266
268
 
298
300
 
299
301
    def _generate_inventory(self):
300
302
        """Create and set self.inventory from the dirstate object.
301
 
        
 
303
 
302
304
        This is relatively expensive: we have to walk the entire dirstate.
303
305
        Ideally we would not, and can deprecate this function.
304
306
        """
349
351
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
350
352
                elif kind == 'tree-reference':
351
353
                    if not self._repo_supports_tree_reference:
352
 
                        raise AssertionError(
353
 
                            "repository of %r "
354
 
                            "doesn't support tree references "
355
 
                            "required by entry %r"
356
 
                            % (self, name))
 
354
                        raise errors.UnsupportedOperation(
 
355
                            self._generate_inventory,
 
356
                            self.branch.repository)
357
357
                    inv_entry.reference_revision = link_or_sha1 or None
358
358
                elif kind != 'symlink':
359
359
                    raise AssertionError("unknown kind %r" % kind)
374
374
        If either file_id or path is supplied, it is used as the key to lookup.
375
375
        If both are supplied, the fastest lookup is used, and an error is
376
376
        raised if they do not both point at the same row.
377
 
        
 
377
 
378
378
        :param file_id: An optional unicode file_id to be looked up.
379
379
        :param path: An optional unicode path to be looked up.
380
380
        :return: The dirstate row tuple for path/file_id, or (None, None)
398
398
        state = self.current_dirstate()
399
399
        if stat_value is None:
400
400
            try:
401
 
                stat_value = os.lstat(file_abspath)
 
401
                stat_value = osutils.lstat(file_abspath)
402
402
            except OSError, e:
403
403
                if e.errno == errno.ENOENT:
404
404
                    return None
419
419
                return link_or_sha1
420
420
        return None
421
421
 
422
 
    def _get_inventory(self):
 
422
    def _get_root_inventory(self):
423
423
        """Get the inventory for the tree. This is only valid within a lock."""
424
424
        if 'evil' in debug.debug_flags:
425
425
            trace.mutter_callsite(2,
430
430
        self._generate_inventory()
431
431
        return self._inventory
432
432
 
 
433
    @deprecated_method(deprecated_in((2, 5, 0)))
 
434
    def _get_inventory(self):
 
435
        return self.root_inventory
 
436
 
433
437
    inventory = property(_get_inventory,
434
438
                         doc="Inventory of this Tree")
435
439
 
 
440
    root_inventory = property(_get_root_inventory,
 
441
        "Root inventory of this tree")
 
442
 
436
443
    @needs_read_lock
437
444
    def get_parent_ids(self):
438
445
        """See Tree.get_parent_ids.
439
 
        
 
446
 
440
447
        This implementation requests the ids list from the dirstate file.
441
448
        """
442
449
        return self.current_dirstate().get_parent_ids()
464
471
        return osutils.lexists(pathjoin(
465
472
                    self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
466
473
 
 
474
    def has_or_had_id(self, file_id):
 
475
        state = self.current_dirstate()
 
476
        row, parents = self._get_entry(file_id=file_id)
 
477
        return row is not None
 
478
 
467
479
    @needs_read_lock
468
480
    def id2path(self, file_id):
469
481
        "Convert a file-id to a path."
480
492
            return False # Missing entries are not executable
481
493
        return entry[1][0][3] # Executable?
482
494
 
483
 
    if not osutils.supports_executable():
484
 
        def is_executable(self, file_id, path=None):
485
 
            """Test if a file is executable or not.
 
495
    def is_executable(self, file_id, path=None):
 
496
        """Test if a file is executable or not.
486
497
 
487
 
            Note: The caller is expected to take a read-lock before calling this.
488
 
            """
 
498
        Note: The caller is expected to take a read-lock before calling this.
 
499
        """
 
500
        if not self._supports_executable():
489
501
            entry = self._get_entry(file_id=file_id, path=path)
490
502
            if entry == (None, None):
491
503
                return False
492
504
            return entry[1][0][3]
493
 
 
494
 
        _is_executable_from_path_and_stat = \
495
 
            _is_executable_from_path_and_stat_from_basis
496
 
    else:
497
 
        def is_executable(self, file_id, path=None):
498
 
            """Test if a file is executable or not.
499
 
 
500
 
            Note: The caller is expected to take a read-lock before calling this.
501
 
            """
 
505
        else:
502
506
            self._must_be_locked()
503
507
            if not path:
504
508
                path = self.id2path(file_id)
505
 
            mode = os.lstat(self.abspath(path)).st_mode
 
509
            mode = osutils.lstat(self.abspath(path)).st_mode
506
510
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
507
511
 
508
512
    def all_file_ids(self):
575
579
    def _kind(self, relpath):
576
580
        abspath = self.abspath(relpath)
577
581
        kind = file_kind(abspath)
578
 
        if (self._repo_supports_tree_reference and
579
 
            kind == 'directory' and
580
 
            self._directory_is_tree_reference(relpath)):
581
 
            kind = 'tree-reference'
 
582
        if (self._repo_supports_tree_reference and kind == 'directory'):
 
583
            entry = self._get_entry(path=relpath)
 
584
            if entry[1] is not None:
 
585
                if entry[1][0][0] == 't':
 
586
                    kind = 'tree-reference'
582
587
        return kind
583
588
 
584
589
    @needs_read_lock
591
596
            return _mod_revision.NULL_REVISION
592
597
 
593
598
    def lock_read(self):
594
 
        """See Branch.lock_read, and WorkingTree.unlock."""
 
599
        """See Branch.lock_read, and WorkingTree.unlock.
 
600
 
 
601
        :return: A bzrlib.lock.LogicalLockResult.
 
602
        """
595
603
        self.branch.lock_read()
596
604
        try:
597
605
            self._control_files.lock_read()
610
618
        except:
611
619
            self.branch.unlock()
612
620
            raise
 
621
        return LogicalLockResult(self.unlock)
613
622
 
614
623
    def _lock_self_write(self):
615
624
        """This should be called after the branch is locked."""
630
639
        except:
631
640
            self.branch.unlock()
632
641
            raise
 
642
        return LogicalLockResult(self.unlock)
633
643
 
634
644
    def lock_tree_write(self):
635
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
645
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
646
 
 
647
        :return: A bzrlib.lock.LogicalLockResult.
 
648
        """
636
649
        self.branch.lock_read()
637
 
        self._lock_self_write()
 
650
        return self._lock_self_write()
638
651
 
639
652
    def lock_write(self):
640
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
653
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
654
 
 
655
        :return: A bzrlib.lock.LogicalLockResult.
 
656
        """
641
657
        self.branch.lock_write()
642
 
        self._lock_self_write()
 
658
        return self._lock_self_write()
643
659
 
644
660
    @needs_tree_write_lock
645
661
    def move(self, from_paths, to_dir, after=False):
676
692
 
677
693
        if self._inventory is not None:
678
694
            update_inventory = True
679
 
            inv = self.inventory
 
695
            inv = self.root_inventory
680
696
            to_dir_id = to_entry[0][2]
681
697
            to_dir_ie = inv[to_dir_id]
682
698
        else:
715
731
            from_entry = self._get_entry(path=from_rel)
716
732
            if from_entry == (None, None):
717
733
                raise errors.BzrMoveFailedError(from_rel,to_dir,
718
 
                    errors.NotVersionedError(path=str(from_rel)))
 
734
                    errors.NotVersionedError(path=from_rel))
719
735
 
720
736
            from_id = from_entry[0][2]
721
737
            to_rel = pathjoin(to_dir, from_tail)
862
878
                rollback_rename()
863
879
                raise
864
880
            result.append((from_rel, to_rel))
865
 
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
 
881
            state._mark_modified()
866
882
            self._make_dirty(reset_inventory=False)
867
883
 
868
884
        return result
896
912
        for tree in trees:
897
913
            if not (isinstance(tree, DirStateRevisionTree) and tree._revision_id in
898
914
                parents):
899
 
                return super(WorkingTree4, self).paths2ids(paths, trees, require_versioned)
 
915
                return super(DirStateWorkingTree, self).paths2ids(paths,
 
916
                    trees, require_versioned)
900
917
        search_indexes = [0] + [1 + parents.index(tree._revision_id) for tree in trees]
901
918
        # -- make all paths utf8 --
902
919
        paths_utf8 = set()
960
977
                    all_versioned = False
961
978
                    break
962
979
            if not all_versioned:
963
 
                raise errors.PathsNotVersionedError(paths)
 
980
                raise errors.PathsNotVersionedError(
 
981
                    [p.decode('utf-8') for p in paths])
964
982
        # -- remove redundancy in supplied paths to prevent over-scanning --
965
983
        search_paths = osutils.minimum_path_selection(paths)
966
 
        # sketch: 
 
984
        # sketch:
967
985
        # for all search_indexs in each path at or under each element of
968
986
        # search_paths, if the detail is relocated: add the id, and add the
969
987
        # relocated path as one to search if its not searched already. If the
1015
1033
            found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
1016
1034
            for dir_name in split_paths:
1017
1035
                if dir_name not in found_dir_names:
1018
 
                    raise errors.PathsNotVersionedError(paths)
 
1036
                    raise errors.PathsNotVersionedError(
 
1037
                        [p.decode('utf-8') for p in paths])
1019
1038
 
1020
1039
        for dir_name_id, trees_info in found.iteritems():
1021
1040
            for index in search_indexes:
1025
1044
 
1026
1045
    def read_working_inventory(self):
1027
1046
        """Read the working inventory.
1028
 
        
 
1047
 
1029
1048
        This is a meaningless operation for dirstate, but we obey it anyhow.
1030
1049
        """
1031
 
        return self.inventory
 
1050
        return self.root_inventory
1032
1051
 
1033
1052
    @needs_read_lock
1034
1053
    def revision_tree(self, revision_id):
1049
1068
    def set_last_revision(self, new_revision):
1050
1069
        """Change the last revision in the working tree."""
1051
1070
        parents = self.get_parent_ids()
1052
 
        if new_revision in (NULL_REVISION, None):
 
1071
        if new_revision in (_mod_revision.NULL_REVISION, None):
1053
1072
            if len(parents) >= 2:
1054
1073
                raise AssertionError(
1055
1074
                    "setting the last parent to none with a pending merge is "
1062
1081
    @needs_tree_write_lock
1063
1082
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
1064
1083
        """Set the parent ids to revision_ids.
1065
 
        
 
1084
 
1066
1085
        See also set_parent_trees. This api will try to retrieve the tree data
1067
1086
        for each element of revision_ids from the trees repository. If you have
1068
1087
        tree data already available, it is more efficient to use
1124
1143
                        _mod_revision.NULL_REVISION)))
1125
1144
                ghosts.append(rev_id)
1126
1145
            accepted_revisions.add(rev_id)
1127
 
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
 
1146
        updated = False
 
1147
        if (len(real_trees) == 1
 
1148
            and not ghosts
 
1149
            and self.branch.repository._format.fast_deltas
 
1150
            and isinstance(real_trees[0][1],
 
1151
                revisiontree.InventoryRevisionTree)
 
1152
            and self.get_parent_ids()):
 
1153
            rev_id, rev_tree = real_trees[0]
 
1154
            basis_id = self.get_parent_ids()[0]
 
1155
            # There are times when basis_tree won't be in
 
1156
            # self.branch.repository, (switch, for example)
 
1157
            try:
 
1158
                basis_tree = self.branch.repository.revision_tree(basis_id)
 
1159
            except errors.NoSuchRevision:
 
1160
                # Fall back to the set_parent_trees(), since we can't use
 
1161
                # _make_delta if we can't get the RevisionTree
 
1162
                pass
 
1163
            else:
 
1164
                delta = rev_tree.root_inventory._make_delta(
 
1165
                    basis_tree.root_inventory)
 
1166
                dirstate.update_basis_by_delta(delta, rev_id)
 
1167
                updated = True
 
1168
        if not updated:
 
1169
            dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1128
1170
        self._make_dirty(reset_inventory=False)
1129
1171
 
1130
1172
    def _set_root_id(self, file_id):
1150
1192
 
1151
1193
    def unlock(self):
1152
1194
        """Unlock in format 4 trees needs to write the entire dirstate."""
1153
 
        # do non-implementation specific cleanup
1154
 
        self._cleanup()
1155
 
 
1156
1195
        if self._control_files._lock_count == 1:
 
1196
            # do non-implementation specific cleanup
 
1197
            self._cleanup()
 
1198
 
1157
1199
            # eventually we should do signature checking during read locks for
1158
1200
            # dirstate updates.
1159
1201
            if self._control_files._lock_mode == 'w':
1222
1264
                # just forget the whole block.
1223
1265
                entry_index = 0
1224
1266
                while entry_index < len(block[1]):
1225
 
                    # Mark this file id as having been removed
1226
1267
                    entry = block[1][entry_index]
1227
 
                    ids_to_unversion.discard(entry[0][2])
1228
 
                    if (entry[1][0][0] in 'ar' # don't remove absent or renamed
1229
 
                                               # entries
1230
 
                        or not state._make_absent(entry)):
 
1268
                    if entry[1][0][0] in 'ar':
 
1269
                        # don't remove absent or renamed entries
1231
1270
                        entry_index += 1
 
1271
                    else:
 
1272
                        # Mark this file id as having been removed
 
1273
                        ids_to_unversion.discard(entry[0][2])
 
1274
                        if not state._make_absent(entry):
 
1275
                            # The block has not shrunk.
 
1276
                            entry_index += 1
1232
1277
                # go to the next block. (At the moment we dont delete empty
1233
1278
                # dirblocks)
1234
1279
                block_index += 1
1255
1300
        # have to change the legacy inventory too.
1256
1301
        if self._inventory is not None:
1257
1302
            for file_id in file_ids:
1258
 
                self._inventory.remove_recursive_id(file_id)
 
1303
                if self._inventory.has_id(file_id):
 
1304
                    self._inventory.remove_recursive_id(file_id)
1259
1305
 
1260
1306
    @needs_tree_write_lock
1261
1307
    def rename_one(self, from_rel, to_rel, after=False):
1262
1308
        """See WorkingTree.rename_one"""
1263
1309
        self.flush()
1264
 
        WorkingTree.rename_one(self, from_rel, to_rel, after)
 
1310
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1265
1311
 
1266
1312
    @needs_tree_write_lock
1267
1313
    def apply_inventory_delta(self, changes):
1286
1332
        if self._dirty:
1287
1333
            raise AssertionError("attempting to write an inventory when the "
1288
1334
                "dirstate is dirty will lose pending changes")
1289
 
        self.current_dirstate().set_state_from_inventory(inv)
1290
 
        self._make_dirty(reset_inventory=False)
1291
 
        if self._inventory is not None:
 
1335
        had_inventory = self._inventory is not None
 
1336
        # Setting self._inventory = None forces the dirstate to regenerate the
 
1337
        # working inventory. We do this because self.inventory may be inv, or
 
1338
        # may have been modified, and either case would prevent a clean delta
 
1339
        # being created.
 
1340
        self._inventory = None
 
1341
        # generate a delta,
 
1342
        delta = inv._make_delta(self.root_inventory)
 
1343
        # and apply it.
 
1344
        self.apply_inventory_delta(delta)
 
1345
        if had_inventory:
1292
1346
            self._inventory = inv
1293
1347
        self.flush()
1294
1348
 
1295
 
 
1296
 
class WorkingTreeFormat4(WorkingTreeFormat3):
1297
 
    """The first consolidated dirstate working tree format.
1298
 
 
1299
 
    This format:
1300
 
        - exists within a metadir controlling .bzr
1301
 
        - includes an explicit version marker for the workingtree control
1302
 
          files, separate from the BzrDir format
1303
 
        - modifies the hash cache format
1304
 
        - is new in bzr 0.15
1305
 
        - uses a LockDir to guard access to it.
1306
 
    """
1307
 
 
1308
 
    upgrade_recommended = False
1309
 
 
1310
 
    _tree_class = WorkingTree4
1311
 
 
1312
 
    def get_format_string(self):
1313
 
        """See WorkingTreeFormat.get_format_string()."""
1314
 
        return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1315
 
 
1316
 
    def get_format_description(self):
1317
 
        """See WorkingTreeFormat.get_format_description()."""
1318
 
        return "Working tree format 4"
 
1349
    @needs_tree_write_lock
 
1350
    def reset_state(self, revision_ids=None):
 
1351
        """Reset the state of the working tree.
 
1352
 
 
1353
        This does a hard-reset to a last-known-good state. This is a way to
 
1354
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
 
1355
        """
 
1356
        if revision_ids is None:
 
1357
            revision_ids = self.get_parent_ids()
 
1358
        if not revision_ids:
 
1359
            base_tree = self.branch.repository.revision_tree(
 
1360
                _mod_revision.NULL_REVISION)
 
1361
            trees = []
 
1362
        else:
 
1363
            trees = zip(revision_ids,
 
1364
                        self.branch.repository.revision_trees(revision_ids))
 
1365
            base_tree = trees[0][1]
 
1366
        state = self.current_dirstate()
 
1367
        # We don't support ghosts yet
 
1368
        state.set_state_from_scratch(base_tree.root_inventory, trees, [])
 
1369
 
 
1370
 
 
1371
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
 
1372
 
 
1373
    def __init__(self, tree):
 
1374
        self.tree = tree
 
1375
 
 
1376
    def sha1(self, abspath):
 
1377
        """See dirstate.SHA1Provider.sha1()."""
 
1378
        filters = self.tree._content_filter_stack(
 
1379
            self.tree.relpath(osutils.safe_unicode(abspath)))
 
1380
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
 
1381
 
 
1382
    def stat_and_sha1(self, abspath):
 
1383
        """See dirstate.SHA1Provider.stat_and_sha1()."""
 
1384
        filters = self.tree._content_filter_stack(
 
1385
            self.tree.relpath(osutils.safe_unicode(abspath)))
 
1386
        file_obj = file(abspath, 'rb', 65000)
 
1387
        try:
 
1388
            statvalue = os.fstat(file_obj.fileno())
 
1389
            if filters:
 
1390
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
 
1391
            sha1 = osutils.size_sha_file(file_obj)[1]
 
1392
        finally:
 
1393
            file_obj.close()
 
1394
        return statvalue, sha1
 
1395
 
 
1396
 
 
1397
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
 
1398
    """Dirstate working tree that supports content filtering.
 
1399
 
 
1400
    The dirstate holds the hash and size of the canonical form of the file, 
 
1401
    and most methods must return that.
 
1402
    """
 
1403
 
 
1404
    def _file_content_summary(self, path, stat_result):
 
1405
        # This is to support the somewhat obsolete path_content_summary method
 
1406
        # with content filtering: see
 
1407
        # <https://bugs.launchpad.net/bzr/+bug/415508>.
 
1408
        #
 
1409
        # If the dirstate cache is up to date and knows the hash and size,
 
1410
        # return that.
 
1411
        # Otherwise if there are no content filters, return the on-disk size
 
1412
        # and leave the hash blank.
 
1413
        # Otherwise, read and filter the on-disk file and use its size and
 
1414
        # hash.
 
1415
        #
 
1416
        # The dirstate doesn't store the size of the canonical form so we
 
1417
        # can't trust it for content-filtered trees.  We just return None.
 
1418
        dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
 
1419
        executable = self._is_executable_from_path_and_stat(path, stat_result)
 
1420
        return ('file', None, executable, dirstate_sha1)
 
1421
 
 
1422
 
 
1423
class WorkingTree4(DirStateWorkingTree):
 
1424
    """This is the Format 4 working tree.
 
1425
 
 
1426
    This differs from WorkingTree by:
 
1427
     - Having a consolidated internal dirstate, stored in a
 
1428
       randomly-accessible sorted file on disk.
 
1429
     - Not having a regular inventory attribute.  One can be synthesized
 
1430
       on demand but this is expensive and should be avoided.
 
1431
 
 
1432
    This is new in bzr 0.15.
 
1433
    """
 
1434
 
 
1435
 
 
1436
class WorkingTree5(ContentFilteringDirStateWorkingTree):
 
1437
    """This is the Format 5 working tree.
 
1438
 
 
1439
    This differs from WorkingTree4 by:
 
1440
     - Supporting content filtering.
 
1441
 
 
1442
    This is new in bzr 1.11.
 
1443
    """
 
1444
 
 
1445
 
 
1446
class WorkingTree6(ContentFilteringDirStateWorkingTree):
 
1447
    """This is the Format 6 working tree.
 
1448
 
 
1449
    This differs from WorkingTree5 by:
 
1450
     - Supporting a current view that may mask the set of files in a tree
 
1451
       impacted by most user operations.
 
1452
 
 
1453
    This is new in bzr 1.14.
 
1454
    """
 
1455
 
 
1456
    def _make_views(self):
 
1457
        return views.PathBasedViews(self)
 
1458
 
 
1459
 
 
1460
class DirStateWorkingTreeFormat(WorkingTreeFormatMetaDir):
 
1461
 
 
1462
    missing_parent_conflicts = True
 
1463
 
 
1464
    supports_versioned_directories = True
 
1465
 
 
1466
    _lock_class = LockDir
 
1467
    _lock_file_name = 'lock'
 
1468
 
 
1469
    def _open_control_files(self, a_bzrdir):
 
1470
        transport = a_bzrdir.get_workingtree_transport(None)
 
1471
        return LockableFiles(transport, self._lock_file_name,
 
1472
                             self._lock_class)
1319
1473
 
1320
1474
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1321
1475
                   accelerator_tree=None, hardlink=False):
1322
1476
        """See WorkingTreeFormat.initialize().
1323
1477
 
1324
1478
        :param revision_id: allows creating a working tree at a different
1325
 
        revision than the branch is at.
 
1479
            revision than the branch is at.
1326
1480
        :param accelerator_tree: A tree which can be used for retrieving file
1327
1481
            contents more quickly than the revision tree, i.e. a workingtree.
1328
1482
            The revision tree will be used for cases where accelerator_tree's
1339
1493
        control_files = self._open_control_files(a_bzrdir)
1340
1494
        control_files.create_lock()
1341
1495
        control_files.lock_write()
1342
 
        transport.put_bytes('format', self.get_format_string(),
 
1496
        transport.put_bytes('format', self.as_string(),
1343
1497
            mode=a_bzrdir._get_file_mode())
1344
1498
        if from_branch is not None:
1345
1499
            branch = from_branch
1361
1515
        wt.lock_tree_write()
1362
1516
        try:
1363
1517
            self._init_custom_control_files(wt)
1364
 
            if revision_id in (None, NULL_REVISION):
 
1518
            if revision_id in (None, _mod_revision.NULL_REVISION):
1365
1519
                if branch.repository.supports_rich_root():
1366
1520
                    wt._set_root_id(generate_ids.gen_root_id())
1367
1521
                else:
1378
1532
                    pass
1379
1533
            if basis is None:
1380
1534
                basis = branch.repository.revision_tree(revision_id)
1381
 
            if revision_id == NULL_REVISION:
 
1535
            if revision_id == _mod_revision.NULL_REVISION:
1382
1536
                parents_list = []
1383
1537
            else:
1384
1538
                parents_list = [(revision_id, basis)]
1392
1546
                if basis_root_id is not None:
1393
1547
                    wt._set_root_id(basis_root_id)
1394
1548
                    wt.flush()
 
1549
                if wt.supports_content_filtering():
 
1550
                    # The original tree may not have the same content filters
 
1551
                    # applied so we can't safely build the inventory delta from
 
1552
                    # the source tree.
 
1553
                    delta_from_tree = False
 
1554
                else:
 
1555
                    delta_from_tree = True
1395
1556
                # delta_from_tree is safe even for DirStateRevisionTrees,
1396
1557
                # because wt4.apply_inventory_delta does not mutate the input
1397
1558
                # inventory entries.
1398
1559
                transform.build_tree(basis, wt, accelerator_tree,
1399
 
                                     hardlink=hardlink, delta_from_tree=True)
 
1560
                                     hardlink=hardlink,
 
1561
                                     delta_from_tree=delta_from_tree)
 
1562
                for hook in MutableTree.hooks['post_build_tree']:
 
1563
                    hook(wt)
1400
1564
            finally:
1401
1565
                basis.unlock()
1402
1566
        finally:
1406
1570
 
1407
1571
    def _init_custom_control_files(self, wt):
1408
1572
        """Subclasses with custom control files should override this method.
1409
 
        
 
1573
 
1410
1574
        The working tree and control files are locked for writing when this
1411
1575
        method is called.
1412
 
        
 
1576
 
1413
1577
        :param wt: the WorkingTree object
1414
1578
        """
1415
1579
 
 
1580
    def open(self, a_bzrdir, _found=False):
 
1581
        """Return the WorkingTree object for a_bzrdir
 
1582
 
 
1583
        _found is a private parameter, do not use it. It is used to indicate
 
1584
               if format probing has already been done.
 
1585
        """
 
1586
        if not _found:
 
1587
            # we are being called directly and must probe.
 
1588
            raise NotImplementedError
 
1589
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
1590
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
1591
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
 
1592
        return wt
 
1593
 
1416
1594
    def _open(self, a_bzrdir, control_files):
1417
1595
        """Open the tree itself.
1418
1596
 
1426
1604
                           _control_files=control_files)
1427
1605
 
1428
1606
    def __get_matchingbzrdir(self):
 
1607
        return self._get_matchingbzrdir()
 
1608
 
 
1609
    def _get_matchingbzrdir(self):
 
1610
        """Overrideable method to get a bzrdir for testing."""
1429
1611
        # please test against something that will let us do tree references
1430
1612
        return bzrdir.format_registry.make_bzrdir(
1431
1613
            'dirstate-with-subtree')
1433
1615
    _matchingbzrdir = property(__get_matchingbzrdir)
1434
1616
 
1435
1617
 
1436
 
class DirStateRevisionTree(Tree):
1437
 
    """A revision tree pulling the inventory from a dirstate."""
 
1618
class WorkingTreeFormat4(DirStateWorkingTreeFormat):
 
1619
    """The first consolidated dirstate working tree format.
 
1620
 
 
1621
    This format:
 
1622
        - exists within a metadir controlling .bzr
 
1623
        - includes an explicit version marker for the workingtree control
 
1624
          files, separate from the ControlDir format
 
1625
        - modifies the hash cache format
 
1626
        - is new in bzr 0.15
 
1627
        - uses a LockDir to guard access to it.
 
1628
    """
 
1629
 
 
1630
    upgrade_recommended = False
 
1631
 
 
1632
    _tree_class = WorkingTree4
 
1633
 
 
1634
    @classmethod
 
1635
    def get_format_string(cls):
 
1636
        """See WorkingTreeFormat.get_format_string()."""
 
1637
        return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
 
1638
 
 
1639
    def get_format_description(self):
 
1640
        """See WorkingTreeFormat.get_format_description()."""
 
1641
        return "Working tree format 4"
 
1642
 
 
1643
 
 
1644
class WorkingTreeFormat5(DirStateWorkingTreeFormat):
 
1645
    """WorkingTree format supporting content filtering.
 
1646
    """
 
1647
 
 
1648
    upgrade_recommended = False
 
1649
 
 
1650
    _tree_class = WorkingTree5
 
1651
 
 
1652
    @classmethod
 
1653
    def get_format_string(cls):
 
1654
        """See WorkingTreeFormat.get_format_string()."""
 
1655
        return "Bazaar Working Tree Format 5 (bzr 1.11)\n"
 
1656
 
 
1657
    def get_format_description(self):
 
1658
        """See WorkingTreeFormat.get_format_description()."""
 
1659
        return "Working tree format 5"
 
1660
 
 
1661
    def supports_content_filtering(self):
 
1662
        return True
 
1663
 
 
1664
 
 
1665
class WorkingTreeFormat6(DirStateWorkingTreeFormat):
 
1666
    """WorkingTree format supporting views.
 
1667
    """
 
1668
 
 
1669
    upgrade_recommended = False
 
1670
 
 
1671
    _tree_class = WorkingTree6
 
1672
 
 
1673
    @classmethod
 
1674
    def get_format_string(cls):
 
1675
        """See WorkingTreeFormat.get_format_string()."""
 
1676
        return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
 
1677
 
 
1678
    def get_format_description(self):
 
1679
        """See WorkingTreeFormat.get_format_description()."""
 
1680
        return "Working tree format 6"
 
1681
 
 
1682
    def _init_custom_control_files(self, wt):
 
1683
        """Subclasses with custom control files should override this method."""
 
1684
        wt._transport.put_bytes('views', '', mode=wt.bzrdir._get_file_mode())
 
1685
 
 
1686
    def supports_content_filtering(self):
 
1687
        return True
 
1688
 
 
1689
    def supports_views(self):
 
1690
        return True
 
1691
 
 
1692
 
 
1693
class DirStateRevisionTree(InventoryTree):
 
1694
    """A revision tree pulling the inventory from a dirstate.
 
1695
    
 
1696
    Note that this is one of the historical (ie revision) trees cached in the
 
1697
    dirstate for easy access, not the workingtree.
 
1698
    """
1438
1699
 
1439
1700
    def __init__(self, dirstate, revision_id, repository):
1440
1701
        self._dirstate = dirstate
1454
1715
    def annotate_iter(self, file_id,
1455
1716
                      default_revision=_mod_revision.CURRENT_REVISION):
1456
1717
        """See Tree.annotate_iter"""
1457
 
        text_key = (file_id, self.inventory[file_id].revision)
 
1718
        text_key = (file_id, self.get_file_revision(file_id))
1458
1719
        annotations = self._repository.texts.annotate(text_key)
1459
1720
        return [(key[-1], line) for (key, line) in annotations]
1460
1721
 
1461
 
    def _get_ancestors(self, default_revision):
1462
 
        return set(self._repository.get_ancestry(self._revision_id,
1463
 
                                                 topo_sorted=False))
1464
1722
    def _comparison_data(self, entry, path):
1465
1723
        """See Tree._comparison_data."""
1466
1724
        if entry is None:
1509
1767
        If either file_id or path is supplied, it is used as the key to lookup.
1510
1768
        If both are supplied, the fastest lookup is used, and an error is
1511
1769
        raised if they do not both point at the same row.
1512
 
        
 
1770
 
1513
1771
        :param file_id: An optional unicode file_id to be looked up.
1514
1772
        :param path: An optional unicode path to be looked up.
1515
1773
        :return: The dirstate row tuple for path/file_id, or (None, None)
1582
1840
                elif kind == 'directory':
1583
1841
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1584
1842
                elif kind == 'symlink':
1585
 
                    inv_entry.executable = False
1586
 
                    inv_entry.text_size = None
1587
1843
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1588
1844
                elif kind == 'tree-reference':
1589
1845
                    inv_entry.reference_revision = fingerprint or None
1609
1865
        # Make sure the file exists
1610
1866
        entry = self._get_entry(file_id, path=path)
1611
1867
        if entry == (None, None): # do we raise?
1612
 
            return None
 
1868
            raise errors.NoSuchId(self, file_id)
1613
1869
        parent_index = self._get_parent_index()
1614
1870
        last_changed_revision = entry[1][parent_index][4]
1615
 
        return self._repository.get_revision(last_changed_revision).timestamp
 
1871
        try:
 
1872
            rev = self._repository.get_revision(last_changed_revision)
 
1873
        except errors.NoSuchRevision:
 
1874
            raise errors.FileTimestampUnavailable(self.id2path(file_id))
 
1875
        return rev.timestamp
1616
1876
 
1617
1877
    def get_file_sha1(self, file_id, path=None, stat_value=None):
1618
1878
        entry = self._get_entry(file_id=file_id, path=path)
1622
1882
            return parent_details[1]
1623
1883
        return None
1624
1884
 
 
1885
    @needs_read_lock
 
1886
    def get_file_revision(self, file_id):
 
1887
        inv, inv_file_id = self._unpack_file_id(file_id)
 
1888
        return inv[inv_file_id].revision
 
1889
 
1625
1890
    def get_file(self, file_id, path=None):
1626
1891
        return StringIO(self.get_file_text(file_id))
1627
1892
 
1628
 
    def get_file_lines(self, file_id):
1629
 
        return osutils.split_lines(self.get_file_text(file_id))
1630
 
 
1631
1893
    def get_file_size(self, file_id):
1632
1894
        """See Tree.get_file_size"""
1633
 
        return self.inventory[file_id].text_size
 
1895
        inv, inv_file_id = self._unpack_file_id(file_id)
 
1896
        return inv[inv_file_id].text_size
1634
1897
 
1635
 
    def get_file_text(self, file_id):
1636
 
        return list(self.iter_files_bytes([(file_id, None)]))[0][1]
 
1898
    def get_file_text(self, file_id, path=None):
 
1899
        _, content = list(self.iter_files_bytes([(file_id, None)]))[0]
 
1900
        return ''.join(content)
1637
1901
 
1638
1902
    def get_reference_revision(self, file_id, path=None):
1639
 
        return self.inventory[file_id].reference_revision
 
1903
        inv, inv_file_id = self._unpack_file_id(file_id)
 
1904
        return inv[inv_file_id].reference_revision
1640
1905
 
1641
1906
    def iter_files_bytes(self, desired_files):
1642
1907
        """See Tree.iter_files_bytes.
1652
1917
                                       identifier))
1653
1918
        return self._repository.iter_files_bytes(repo_desired_files)
1654
1919
 
1655
 
    def get_symlink_target(self, file_id):
 
1920
    def get_symlink_target(self, file_id, path=None):
1656
1921
        entry = self._get_entry(file_id=file_id)
1657
1922
        parent_index = self._get_parent_index()
1658
1923
        if entry[1][parent_index][0] != 'l':
1659
1924
            return None
1660
1925
        else:
1661
 
            # At present, none of the tree implementations supports non-ascii
1662
 
            # symlink targets. So we will just assume that the dirstate path is
1663
 
            # correct.
1664
 
            return entry[1][parent_index][1]
 
1926
            target = entry[1][parent_index][1]
 
1927
            target = target.decode('utf8')
 
1928
            return target
1665
1929
 
1666
1930
    def get_revision_id(self):
1667
1931
        """Return the revision id for this tree."""
1668
1932
        return self._revision_id
1669
1933
 
1670
 
    def _get_inventory(self):
 
1934
    def _get_root_inventory(self):
1671
1935
        if self._inventory is not None:
1672
1936
            return self._inventory
1673
1937
        self._must_be_locked()
1674
1938
        self._generate_inventory()
1675
1939
        return self._inventory
1676
1940
 
 
1941
    root_inventory = property(_get_root_inventory,
 
1942
                         doc="Inventory of this Tree")
 
1943
 
 
1944
    @deprecated_method(deprecated_in((2, 5, 0)))
 
1945
    def _get_inventory(self):
 
1946
        return self.root_inventory
 
1947
 
1677
1948
    inventory = property(_get_inventory,
1678
1949
                         doc="Inventory of this Tree")
1679
1950
 
1688
1959
        entry = self._get_entry(file_id=file_id)[1]
1689
1960
        if entry is None:
1690
1961
            raise errors.NoSuchId(tree=self, file_id=file_id)
1691
 
        return dirstate.DirState._minikind_to_kind[entry[1][0]]
 
1962
        parent_index = self._get_parent_index()
 
1963
        return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1692
1964
 
1693
1965
    def stored_kind(self, file_id):
1694
1966
        """See Tree.stored_kind"""
1696
1968
 
1697
1969
    def path_content_summary(self, path):
1698
1970
        """See Tree.path_content_summary."""
1699
 
        id = self.inventory.path2id(path)
1700
 
        if id is None:
 
1971
        inv, inv_file_id = self._path2inv_file_id(path)
 
1972
        if inv_file_id is None:
1701
1973
            return ('missing', None, None, None)
1702
 
        entry = self._inventory[id]
 
1974
        entry = inv[inv_file_id]
1703
1975
        kind = entry.kind
1704
1976
        if kind == 'file':
1705
1977
            return (kind, entry.text_size, entry.executable, entry.text_sha1)
1709
1981
            return (kind, None, None, None)
1710
1982
 
1711
1983
    def is_executable(self, file_id, path=None):
1712
 
        ie = self.inventory[file_id]
 
1984
        inv, inv_file_id = self._unpack_file_id(file_id)
 
1985
        ie = inv[inv_file_id]
1713
1986
        if ie.kind != "file":
1714
 
            return None
 
1987
            return False
1715
1988
        return ie.executable
1716
1989
 
1717
 
    def list_files(self, include_root=False):
 
1990
    def is_locked(self):
 
1991
        return self._locked
 
1992
 
 
1993
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1718
1994
        # We use a standard implementation, because DirStateRevisionTree is
1719
1995
        # dealing with one of the parents of the current state
1720
 
        inv = self._get_inventory()
1721
 
        entries = inv.iter_entries()
1722
 
        if self.inventory.root is not None and not include_root:
 
1996
        if from_dir is None:
 
1997
            inv = self.root_inventory
 
1998
            from_dir_id = None
 
1999
        else:
 
2000
            inv, from_dir_id = self._path2inv_file_id(from_dir)
 
2001
            if from_dir_id is None:
 
2002
                # Directory not versioned
 
2003
                return
 
2004
        # FIXME: Support nested trees
 
2005
        entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
 
2006
        if inv.root is not None and not include_root and from_dir is None:
1723
2007
            entries.next()
1724
2008
        for path, entry in entries:
1725
2009
            yield path, 'V', entry.kind, entry.file_id, entry
1726
2010
 
1727
2011
    def lock_read(self):
1728
 
        """Lock the tree for a set of operations."""
 
2012
        """Lock the tree for a set of operations.
 
2013
 
 
2014
        :return: A bzrlib.lock.LogicalLockResult.
 
2015
        """
1729
2016
        if not self._locked:
1730
2017
            self._repository.lock_read()
1731
2018
            if self._dirstate._lock_token is None:
1732
2019
                self._dirstate.lock_read()
1733
2020
                self._dirstate_locked = True
1734
2021
        self._locked += 1
 
2022
        return LogicalLockResult(self.unlock)
1735
2023
 
1736
2024
    def _must_be_locked(self):
1737
2025
        if not self._locked:
1764
2052
 
1765
2053
    def walkdirs(self, prefix=""):
1766
2054
        # TODO: jam 20070215 This is the lazy way by using the RevisionTree
1767
 
        # implementation based on an inventory.  
 
2055
        # implementation based on an inventory.
1768
2056
        # This should be cleaned up to use the much faster Dirstate code
1769
2057
        # So for now, we just build up the parent inventory, and extract
1770
2058
        # it the same way RevisionTree does.
1771
2059
        _directory = 'directory'
1772
 
        inv = self._get_inventory()
 
2060
        inv = self._get_root_inventory()
1773
2061
        top_id = inv.path2id(prefix)
1774
2062
        if top_id is None:
1775
2063
            pending = []
1799
2087
 
1800
2088
class InterDirStateTree(InterTree):
1801
2089
    """Fast path optimiser for changes_from with dirstate trees.
1802
 
    
1803
 
    This is used only when both trees are in the dirstate working file, and 
1804
 
    the source is any parent within the dirstate, and the destination is 
 
2090
 
 
2091
    This is used only when both trees are in the dirstate working file, and
 
2092
    the source is any parent within the dirstate, and the destination is
1805
2093
    the current working tree of the same dirstate.
1806
2094
    """
1807
2095
    # this could be generalized to allow comparisons between any trees in the
1816
2104
    def make_source_parent_tree(source, target):
1817
2105
        """Change the source tree into a parent of the target."""
1818
2106
        revid = source.commit('record tree')
1819
 
        target.branch.repository.fetch(source.branch.repository, revid)
 
2107
        target.branch.fetch(source.branch, revid)
1820
2108
        target.set_parent_ids([revid])
1821
2109
        return target.basis_tree(), target
1822
2110
 
1827
2115
        return result
1828
2116
 
1829
2117
    @classmethod
1830
 
    def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
 
2118
    def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
 
2119
                                                  target):
1831
2120
        from bzrlib.tests.test__dirstate_helpers import \
1832
 
            CompiledDirstateHelpersFeature
1833
 
        if not CompiledDirstateHelpersFeature.available():
1834
 
            from bzrlib.tests import UnavailableFeature
1835
 
            raise UnavailableFeature(CompiledDirstateHelpersFeature)
1836
 
        from bzrlib._dirstate_helpers_c import ProcessEntryC
 
2121
            compiled_dirstate_helpers_feature
 
2122
        test_case.requireFeature(compiled_dirstate_helpers_feature)
 
2123
        from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1837
2124
        result = klass.make_source_parent_tree(source, target)
1838
2125
        result[1]._iter_changes = ProcessEntryC
1839
2126
        return result
1869
2156
            output. An unversioned file is defined as one with (False, False)
1870
2157
            for the versioned pair.
1871
2158
        """
1872
 
        # NB: show_status depends on being able to pass in non-versioned files
1873
 
        # and report them as unknown
1874
2159
        # TODO: handle extra trees in the dirstate.
1875
2160
        if (extra_trees or specific_files == []):
1876
2161
            # we can't fast-path these cases (yet)
1879
2164
                require_versioned, want_unversioned=want_unversioned)
1880
2165
        parent_ids = self.target.get_parent_ids()
1881
2166
        if not (self.source._revision_id in parent_ids
1882
 
                or self.source._revision_id == NULL_REVISION):
 
2167
                or self.source._revision_id == _mod_revision.NULL_REVISION):
1883
2168
            raise AssertionError(
1884
2169
                "revision {%s} is not stored in {%s}, but %s "
1885
2170
                "can only be used for trees stored in the dirstate"
1886
2171
                % (self.source._revision_id, self.target, self.iter_changes))
1887
2172
        target_index = 0
1888
 
        if self.source._revision_id == NULL_REVISION:
 
2173
        if self.source._revision_id == _mod_revision.NULL_REVISION:
1889
2174
            source_index = None
1890
2175
            indices = (target_index,)
1891
2176
        else:
1906
2191
        else:
1907
2192
            specific_files = set([''])
1908
2193
        # -- specific_files is now a utf8 path set --
1909
 
        search_specific_files = set()
 
2194
 
1910
2195
        # -- get the state object and prepare it.
1911
2196
        state = self.target.current_dirstate()
1912
2197
        state._read_dirblocks_if_needed()
1913
2198
        if require_versioned:
1914
2199
            # -- check all supplied paths are versioned in a search tree. --
1915
 
            all_versioned = True
 
2200
            not_versioned = []
1916
2201
            for path in specific_files:
1917
2202
                path_entries = state._entries_for_path(path)
1918
2203
                if not path_entries:
1919
2204
                    # this specified path is not present at all: error
1920
 
                    all_versioned = False
1921
 
                    break
 
2205
                    not_versioned.append(path.decode('utf-8'))
 
2206
                    continue
1922
2207
                found_versioned = False
1923
2208
                # for each id at this path
1924
2209
                for entry in path_entries:
1931
2216
                if not found_versioned:
1932
2217
                    # none of the indexes was not 'absent' at all ids for this
1933
2218
                    # path.
1934
 
                    all_versioned = False
1935
 
                    break
1936
 
            if not all_versioned:
1937
 
                raise errors.PathsNotVersionedError(specific_files)
 
2219
                    not_versioned.append(path.decode('utf-8'))
 
2220
            if len(not_versioned) > 0:
 
2221
                raise errors.PathsNotVersionedError(not_versioned)
1938
2222
        # -- remove redundancy in supplied specific_files to prevent over-scanning --
1939
 
        for path in specific_files:
1940
 
            other_specific_files = specific_files.difference(set([path]))
1941
 
            if not osutils.is_inside_any(other_specific_files, path):
1942
 
                # this is a top level path, we must check it.
1943
 
                search_specific_files.add(path)
 
2223
        search_specific_files = osutils.minimum_path_selection(specific_files)
1944
2224
 
1945
2225
        use_filesystem_for_exec = (sys.platform != 'win32')
1946
2226
        iter_changes = self.target._iter_changes(include_unchanged,
1951
2231
    @staticmethod
1952
2232
    def is_compatible(source, target):
1953
2233
        # the target must be a dirstate working tree
1954
 
        if not isinstance(target, WorkingTree4):
 
2234
        if not isinstance(target, DirStateWorkingTree):
1955
2235
            return False
1956
 
        # the source must be a revtreee or dirstate rev tree.
 
2236
        # the source must be a revtree or dirstate rev tree.
1957
2237
        if not isinstance(source,
1958
2238
            (revisiontree.RevisionTree, DirStateRevisionTree)):
1959
2239
            return False
1960
2240
        # the source revid must be in the target dirstate
1961
 
        if not (source._revision_id == NULL_REVISION or
 
2241
        if not (source._revision_id == _mod_revision.NULL_REVISION or
1962
2242
            source._revision_id in target.get_parent_ids()):
1963
 
            # TODO: what about ghosts? it may well need to 
 
2243
            # TODO: what about ghosts? it may well need to
1964
2244
            # check for them explicitly.
1965
2245
            return False
1966
2246
        return True
1976
2256
 
1977
2257
    def convert(self, tree):
1978
2258
        # lock the control files not the tree, so that we dont get tree
1979
 
        # on-unlock behaviours, and so that noone else diddles with the 
 
2259
        # on-unlock behaviours, and so that noone else diddles with the
1980
2260
        # tree during upgrade.
1981
2261
        tree._control_files.lock_write()
1982
2262
        try:
2009
2289
    def update_format(self, tree):
2010
2290
        """Change the format marker."""
2011
2291
        tree._transport.put_bytes('format',
2012
 
            self.target_format.get_format_string(),
 
2292
            self.target_format.as_string(),
 
2293
            mode=tree.bzrdir._get_file_mode())
 
2294
 
 
2295
 
 
2296
class Converter4to5(object):
 
2297
    """Perform an in-place upgrade of format 4 to format 5 trees."""
 
2298
 
 
2299
    def __init__(self):
 
2300
        self.target_format = WorkingTreeFormat5()
 
2301
 
 
2302
    def convert(self, tree):
 
2303
        # lock the control files not the tree, so that we don't get tree
 
2304
        # on-unlock behaviours, and so that no-one else diddles with the
 
2305
        # tree during upgrade.
 
2306
        tree._control_files.lock_write()
 
2307
        try:
 
2308
            self.update_format(tree)
 
2309
        finally:
 
2310
            tree._control_files.unlock()
 
2311
 
 
2312
    def update_format(self, tree):
 
2313
        """Change the format marker."""
 
2314
        tree._transport.put_bytes('format',
 
2315
            self.target_format.as_string(),
 
2316
            mode=tree.bzrdir._get_file_mode())
 
2317
 
 
2318
 
 
2319
class Converter4or5to6(object):
 
2320
    """Perform an in-place upgrade of format 4 or 5 to format 6 trees."""
 
2321
 
 
2322
    def __init__(self):
 
2323
        self.target_format = WorkingTreeFormat6()
 
2324
 
 
2325
    def convert(self, tree):
 
2326
        # lock the control files not the tree, so that we don't get tree
 
2327
        # on-unlock behaviours, and so that no-one else diddles with the
 
2328
        # tree during upgrade.
 
2329
        tree._control_files.lock_write()
 
2330
        try:
 
2331
            self.init_custom_control_files(tree)
 
2332
            self.update_format(tree)
 
2333
        finally:
 
2334
            tree._control_files.unlock()
 
2335
 
 
2336
    def init_custom_control_files(self, tree):
 
2337
        """Initialize custom control files."""
 
2338
        tree._transport.put_bytes('views', '',
 
2339
            mode=tree.bzrdir._get_file_mode())
 
2340
 
 
2341
    def update_format(self, tree):
 
2342
        """Change the format marker."""
 
2343
        tree._transport.put_bytes('format',
 
2344
            self.target_format.as_string(),
2013
2345
            mode=tree.bzrdir._get_file_mode())