/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2255.2.157 by Martin Pool
merge merge_modified test and cleanups
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""WorkingTree4 format and implementation.
18
19
WorkingTree4 provides the dirstate based working tree logic.
20
21
To get a WorkingTree, call bzrdir.open_workingtree() or
22
WorkingTree.open(dir).
23
"""
24
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
25
from cStringIO import StringIO
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
26
import os
2255.2.138 by John Arbash Meinel
implement several new WorkingTree.move() tests
27
import sys
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
28
29
from bzrlib.lazy_import import lazy_import
30
lazy_import(globals(), """
31
from bisect import bisect_left
32
import collections
33
from copy import deepcopy
34
import errno
35
import itertools
36
import operator
37
import stat
38
from time import time
39
import warnings
40
41
import bzrlib
42
from bzrlib import (
43
    bzrdir,
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
44
    cache_utf8,
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
45
    conflicts as _mod_conflicts,
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
46
    delta,
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
47
    dirstate,
48
    errors,
49
    generate_ids,
50
    globbing,
51
    hashcache,
52
    ignores,
53
    merge,
54
    osutils,
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
55
    revisiontree,
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
56
    textui,
57
    transform,
58
    urlutils,
59
    xml5,
60
    xml6,
61
    )
62
import bzrlib.branch
63
from bzrlib.transport import get_transport
64
import bzrlib.ui
65
""")
66
67
from bzrlib import symbol_versioning
68
from bzrlib.decorators import needs_read_lock, needs_write_lock
2255.2.74 by Robert Collins
Minor performance optimisation in _generate_inventory by avoiding normalisation checks and just using a factory to create the inventory entries.
69
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
70
from bzrlib.lockable_files import LockableFiles, TransportLock
71
from bzrlib.lockdir import LockDir
72
import bzrlib.mutabletree
73
from bzrlib.mutabletree import needs_tree_write_lock
74
from bzrlib.osutils import (
75
    compact_date,
76
    file_kind,
77
    isdir,
78
    normpath,
79
    pathjoin,
80
    rand_chars,
81
    realpath,
82
    safe_unicode,
83
    splitpath,
84
    supports_executable,
85
    )
86
from bzrlib.trace import mutter, note
87
from bzrlib.transport.local import LocalTransport
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
88
from bzrlib.tree import InterTree
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
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
        zero_eight,
97
        zero_eleven,
98
        zero_thirteen,
99
        )
100
from bzrlib.tree import Tree
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
101
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
102
103
104
class WorkingTree4(WorkingTree3):
105
    """This is the Format 4 working tree.
106
107
    This differs from WorkingTree3 by:
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
108
     - Having a consolidated internal dirstate, stored in a
109
       randomly-accessible sorted file on disk.
110
     - Not having a regular inventory attribute.  One can be synthesized 
111
       on demand but this is expensive and should be avoided.
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
112
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
113
    This is new in bzr 0.15.
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
114
    """
115
116
    def __init__(self, basedir,
117
                 branch,
118
                 _control_files=None,
119
                 _format=None,
120
                 _bzrdir=None):
121
        """Construct a WorkingTree for basedir.
122
123
        If the branch is not supplied, it is opened automatically.
124
        If the branch is supplied, it must be the branch for this basedir.
125
        (branch.base is not cross checked, because for remote branches that
126
        would be meaningless).
127
        """
128
        self._format = _format
129
        self.bzrdir = _bzrdir
130
        from bzrlib.hashcache import HashCache
131
        from bzrlib.trace import note, mutter
132
        assert isinstance(basedir, basestring), \
133
            "base directory %r is not a string" % basedir
134
        basedir = safe_unicode(basedir)
135
        mutter("opening working tree %r", basedir)
136
        self._branch = branch
137
        assert isinstance(self.branch, bzrlib.branch.Branch), \
138
            "branch %r is not a Branch" % self.branch
139
        self.basedir = realpath(basedir)
140
        # if branch is at our basedir and is a format 6 or less
141
        # assume all other formats have their own control files.
142
        assert isinstance(_control_files, LockableFiles), \
143
            "_control_files must be a LockableFiles, not %r" % _control_files
144
        self._control_files = _control_files
145
        # update the whole cache up front and write to disk if anything changed;
146
        # in the future we might want to do this more selectively
147
        # two possible ways offer themselves : in self._unlock, write the cache
148
        # if needed, or, when the cache sees a change, append it to the hash
149
        # cache file, and have the parser take the most recent entry for a
150
        # given path only.
151
        cache_filename = self.bzrdir.get_workingtree_transport(None).local_abspath('stat-cache')
152
        hc = self._hashcache = HashCache(basedir, cache_filename, self._control_files._file_mode)
153
        hc.read()
154
        # is this scan needed ? it makes things kinda slow.
155
        #hc.scan()
156
157
        if hc.needs_write:
158
            mutter("write hc")
159
            hc.write()
160
161
        self._dirty = None
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
162
        #-------------
163
        # during a read or write lock these objects are set, and are
164
        # None the rest of the time.
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
165
        self._dirstate = None
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
166
        self._inventory = None
167
        #-------------
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
168
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
169
    @needs_tree_write_lock
2255.2.12 by Robert Collins
Partial implementation of WorkingTree4._add.
170
    def _add(self, files, ids, kinds):
171
        """See MutableTree._add."""
172
        state = self.current_dirstate()
173
        for f, file_id, kind in zip(files, ids, kinds):
2255.2.14 by Robert Collins
Dirstate: fix adding of directories to setup the next directories block, and test representation of symlinks. Also fix iter_rows to not reset the dirty bit.
174
            f = f.strip('/')
2255.2.12 by Robert Collins
Partial implementation of WorkingTree4._add.
175
            assert '//' not in f
176
            assert '..' not in f
177
            if file_id is None:
2255.2.20 by Robert Collins
Bypass irrelevant basis_inventory tests for dirstate.
178
                file_id = generate_ids.gen_file_id(f)
2255.2.43 by Robert Collins
WorkingTree4.add must not require a file to exist to add it when kind etc is given.
179
            # deliberately add the file with no cached stat or sha1
180
            # - on the first access it will be gathered, and we can
181
            # always change this once tests are all passing.
182
            state.add(f, file_id, kind, None, '')
2255.2.16 by Robert Collins
Implement WorkingTreeFormat4._write_inventory for better compatability with existing code, letting more test_test_trees pass, now up to test_tree_with_subdirs_and_all_content_types.
183
        self._dirty = True
2255.2.12 by Robert Collins
Partial implementation of WorkingTree4._add.
184
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
185
    @needs_tree_write_lock
186
    def add_reference(self, sub_tree):
187
        # use standard implementation, which calls back to self._add
188
        # 
189
        # So we don't store the reference_revision in the working dirstate,
190
        # it's just recorded at the moment of commit. 
191
        self._add_reference(sub_tree)
192
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
193
    def break_lock(self):
194
        """Break a lock if one is present from another instance.
195
196
        Uses the ui factory to ask for confirmation if the lock may be from
197
        an active process.
198
199
        This will probe the repository for its lock as well.
200
        """
201
        # if the dirstate is locked by an active process, reject the break lock
202
        # call.
203
        try:
204
            if self._dirstate is None:
205
                clear = True
206
            else:
207
                clear = False
208
            state = self._current_dirstate()
209
            if state._lock_token is not None:
210
                # we already have it locked. sheese, cant break our own lock.
211
                raise errors.LockActive(self.basedir)
212
            else:
213
                try:
214
                    # try for a write lock - need permission to get one anyhow
215
                    # to break locks.
216
                    state.lock_write()
217
                except errors.LockContention:
218
                    # oslocks fail when a process is still live: fail.
219
                    # TODO: get the locked lockdir info and give to the user to
220
                    # assist in debugging.
221
                    raise errors.LockActive(self.basedir)
222
                else:
223
                    state.unlock()
224
        finally:
225
            if clear:
226
                self._dirstate = None
227
        self._control_files.break_lock()
228
        self.branch.break_lock()
229
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
230
    def _comparison_data(self, entry, path):
231
        kind, executable, stat_value = \
232
            WorkingTree3._comparison_data(self, entry, path)
233
        # it looks like a plain directory, but it's really a reference
234
        if kind == 'directory' and entry.kind == 'tree-reference':
235
            kind = 'tree-reference'
236
        return kind, executable, stat_value
237
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
238
    def current_dirstate(self):
239
        """Return the current dirstate object. 
240
241
        This is not part of the tree interface and only exposed for ease of
242
        testing.
243
244
        :raises errors.NotWriteLocked: when not in a lock. 
245
        """
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
246
        self._must_be_locked()
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
247
        return self._current_dirstate()
248
249
    def _current_dirstate(self):
250
        """Internal function that does not check lock status.
251
        
252
        This is needed for break_lock which also needs the dirstate.
253
        """
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
254
        if self._dirstate is not None:
255
            return self._dirstate
256
        local_path = self.bzrdir.get_workingtree_transport(None
257
            ).local_abspath('dirstate')
258
        self._dirstate = dirstate.DirState.on_file(local_path)
259
        return self._dirstate
260
2255.2.81 by Robert Collins
WorkingTree4: Implement filter_unversioned_files to use dirstate bisection.
261
    def filter_unversioned_files(self, paths):
262
        """Filter out paths that are not versioned.
263
264
        :return: set of paths.
265
        """
266
        # TODO: make a generic multi-bisect routine roughly that should list
267
        # the paths, then process one half at a time recursively, and feed the
268
        # results of each bisect in further still
269
        paths = sorted(paths)
270
        result = set()
271
        state = self.current_dirstate()
272
        # TODO we want a paths_to_dirblocks helper I think
273
        for path in paths:
274
            dirname, basename = os.path.split(path.encode('utf8'))
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
275
            _, _, _, path_is_versioned = state._get_block_entry_index(
276
                dirname, basename, 0)
2255.2.81 by Robert Collins
WorkingTree4: Implement filter_unversioned_files to use dirstate bisection.
277
            if path_is_versioned:
278
                result.add(path)
279
        return result
280
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
281
    def flush(self):
282
        """Write all cached data to disk."""
2255.2.39 by Robert Collins
WorkingTree4: flush can only be used during write locks.
283
        if self._control_files._lock_mode != 'w':
284
            raise errors.NotWriteLocked(self)
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
285
        self.current_dirstate().save()
286
        self._inventory = None
287
        self._dirty = False
288
2255.2.34 by Robert Collins
Fix WorkingTree4 parent_ids logic to use the dirstate to answer parent ids list queries.
289
    def _generate_inventory(self):
290
        """Create and set self.inventory from the dirstate object.
291
        
292
        This is relatively expensive: we have to walk the entire dirstate.
293
        Ideally we would not, and can deprecate this function.
294
        """
2255.2.82 by Robert Collins
various notes about find_ids_across_trees
295
        #: uncomment to trap on inventory requests.
296
        # import pdb;pdb.set_trace()
2255.2.75 by Robert Collins
Correct generation of revisiontree inventories to handle out of order parents.
297
        state = self.current_dirstate()
298
        state._read_dirblocks_if_needed()
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
299
        root_key, current_entry = self._get_entry(path='')
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
300
        current_id = root_key[2]
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
301
        assert current_entry[0][0] == 'd' # directory
2255.2.75 by Robert Collins
Correct generation of revisiontree inventories to handle out of order parents.
302
        inv = Inventory(root_id=current_id)
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
303
        # Turn some things into local variables
304
        minikind_to_kind = dirstate.DirState._minikind_to_kind
305
        factory = entry_factory
306
        utf8_decode = cache_utf8._utf8_decode
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
307
        inv_byid = inv._byid
2255.2.73 by Robert Collins
50% speedup in the dirstate->inventory conversion logic by caching the parent ids as we walk the tree. Some further work would be to maintain a stack of parents as we know we visit depth first.
308
        # we could do this straight out of the dirstate; it might be fast
309
        # and should be profiled - RBC 20070216
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
310
        parent_ies = {'' : inv.root}
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
311
        for block in state._dirblocks[1:]: # skip the root
2255.2.77 by Robert Collins
Tune working inventory generation more: walk the blocks, skipping deleted rows.
312
            dirname = block[0]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
313
            try:
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
314
                parent_ie = parent_ies[dirname]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
315
            except KeyError:
316
                # all the paths in this block are not versioned in this tree
317
                continue
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
318
            for key, entry in block[1]:
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
319
                minikind, link_or_sha1, size, executable, stat = entry[0]
320
                if minikind in ('a', 'r'): # absent, relocated
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
321
                    # a parent tree only entry
322
                    continue
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
323
                name = key[1]
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
324
                name_unicode = utf8_decode(name)[0]
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
325
                file_id = key[2]
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
326
                kind = minikind_to_kind[minikind]
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
327
                inv_entry = factory[kind](file_id, name_unicode,
328
                                          parent_ie.file_id)
2255.2.77 by Robert Collins
Tune working inventory generation more: walk the blocks, skipping deleted rows.
329
                if kind == 'file':
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
330
                    # not strictly needed: working tree
2255.2.77 by Robert Collins
Tune working inventory generation more: walk the blocks, skipping deleted rows.
331
                    #entry.executable = executable
332
                    #entry.text_size = size
333
                    #entry.text_sha1 = sha1
334
                    pass
335
                elif kind == 'directory':
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
336
                    # add this entry to the parent map.
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
337
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
338
                # These checks cost us around 40ms on a 55k entry tree
2255.7.15 by John Arbash Meinel
Try to create an intertree test that exposes the walkdir vs dirstate mismatch. No luck yet.
339
                assert file_id not in inv_byid, ('file_id %s already in'
340
                    ' inventory as %s' % (file_id, inv_byid[file_id]))
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
341
                assert name_unicode not in parent_ie.children
342
                inv_byid[file_id] = inv_entry
343
                parent_ie.children[name_unicode] = inv_entry
2255.2.34 by Robert Collins
Fix WorkingTree4 parent_ids logic to use the dirstate to answer parent ids list queries.
344
        self._inventory = inv
345
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
346
    def _get_entry(self, file_id=None, path=None):
347
        """Get the dirstate row for file_id or path.
348
349
        If either file_id or path is supplied, it is used as the key to lookup.
350
        If both are supplied, the fastest lookup is used, and an error is
351
        raised if they do not both point at the same row.
352
        
353
        :param file_id: An optional unicode file_id to be looked up.
354
        :param path: An optional unicode path to be looked up.
355
        :return: The dirstate row tuple for path/file_id, or (None, None)
356
        """
357
        if file_id is None and path is None:
358
            raise errors.BzrError('must supply file_id or path')
359
        state = self.current_dirstate()
360
        if path is not None:
361
            path = path.encode('utf8')
362
        return state._get_entry(0, fileid_utf8=file_id, path_utf8=path)
363
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
364
    def get_file_sha1(self, file_id, path=None, stat_value=None):
2255.2.88 by Robert Collins
Significant steps back to operation.
365
        # check file id is valid unconditionally.
2255.2.95 by Robert Collins
Fix WorkingTree4.get_file_sha1 to actually work.
366
        key, details = self._get_entry(file_id=file_id, path=path)
367
        assert key is not None, 'what error should this raise'
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
368
        # TODO:
369
        # if row stat is valid, use cached sha1, else, get a new sha1.
2255.2.73 by Robert Collins
50% speedup in the dirstate->inventory conversion logic by caching the parent ids as we walk the tree. Some further work would be to maintain a stack of parents as we know we visit depth first.
370
        if path is None:
2255.2.95 by Robert Collins
Fix WorkingTree4.get_file_sha1 to actually work.
371
            path = os.path.join(*key[0:2]).decode('utf8')
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
372
        return self._hashcache.get_sha1(path, stat_value)
373
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
374
    def _get_inventory(self):
375
        """Get the inventory for the tree. This is only valid within a lock."""
376
        if self._inventory is not None:
377
            return self._inventory
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
378
        self._must_be_locked()
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
379
        self._generate_inventory()
380
        return self._inventory
381
382
    inventory = property(_get_inventory,
383
                         doc="Inventory of this Tree")
384
385
    @needs_read_lock
2255.2.34 by Robert Collins
Fix WorkingTree4 parent_ids logic to use the dirstate to answer parent ids list queries.
386
    def get_parent_ids(self):
387
        """See Tree.get_parent_ids.
388
        
389
        This implementation requests the ids list from the dirstate file.
390
        """
391
        return self.current_dirstate().get_parent_ids()
392
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
393
    def get_reference_revision(self, entry, path=None):
394
        # referenced tree's revision is whatever's currently there
395
        return self.get_nested_tree(entry, path).last_revision()
396
397
    def get_nested_tree(self, entry, path=None):
398
        if path is None:
399
            path = self.id2path(entry.file_id)
400
        return WorkingTree.open(self.abspath(path))
401
2255.2.34 by Robert Collins
Fix WorkingTree4 parent_ids logic to use the dirstate to answer parent ids list queries.
402
    @needs_read_lock
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
403
    def get_root_id(self):
404
        """Return the id of this trees root"""
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
405
        return self._get_entry(path='')[0][2]
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
406
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
407
    def has_id(self, file_id):
408
        state = self.current_dirstate()
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
409
        file_id = osutils.safe_file_id(file_id)
2255.2.92 by James Westby
Make the WorkingTree4 has_id use the new _get_entry rather than _get_row.
410
        row, parents = self._get_entry(file_id=file_id)
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
411
        if row is None:
412
            return False
413
        return osutils.lexists(pathjoin(
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
414
                    self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
415
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
416
    @needs_read_lock
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
417
    def id2path(self, file_id):
418
        file_id = osutils.safe_file_id(file_id)
419
        state = self.current_dirstate()
2255.2.147 by John Arbash Meinel
Move fast id => path lookups down into DirState
420
        entry = self._get_entry(file_id=file_id)
421
        if entry == (None, None):
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
422
            return None
2255.2.147 by John Arbash Meinel
Move fast id => path lookups down into DirState
423
        path_utf8 = osutils.pathjoin(entry[0][0], entry[0][1])
424
        return path_utf8.decode('utf8')
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
425
426
    @needs_read_lock
427
    def __iter__(self):
428
        """Iterate through file_ids for this tree.
429
430
        file_ids are in a WorkingTree if they are in the working inventory
431
        and the working file exists.
432
        """
433
        result = []
2255.2.88 by Robert Collins
Significant steps back to operation.
434
        for key, tree_details in self.current_dirstate()._iter_entries():
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
435
            if tree_details[0][0] in ('a', 'r'): # absent, relocated
2255.2.88 by Robert Collins
Significant steps back to operation.
436
                # not relevant to the working tree
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
437
                continue
2255.2.88 by Robert Collins
Significant steps back to operation.
438
            path = pathjoin(self.basedir, key[0].decode('utf8'), key[1].decode('utf8'))
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
439
            if osutils.lexists(path):
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
440
                result.append(key[2])
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
441
        return iter(result)
442
2255.2.159 by Martin Pool
reference-trees in dirstate pass all tests.
443
    @needs_read_lock
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
444
    def kind(self, file_id):
445
        # The kind of a file is whatever it actually is on disk, except that 
446
        # tree-references need to be reported as such rather than as the
447
        # directiories
448
        #
449
        # TODO: Possibly we should check that the directory still really
450
        # contains a subtree, at least during commit? mbp 20070227
451
        kind = WorkingTree3.kind(self, file_id)
452
        if kind == 'directory':
453
            # TODO: ask the dirstate not the inventory -- mbp 20060227
454
            entry = self.inventory[file_id]
455
            if entry.kind == 'tree-reference':
456
                kind = 'tree-reference'
457
        return kind
458
2255.2.21 by Robert Collins
Add WorkingTree4._last_revision, making workingtree_implementations.test_changes_from pass.
459
    @needs_read_lock
460
    def _last_revision(self):
461
        """See Mutable.last_revision."""
462
        parent_ids = self.current_dirstate().get_parent_ids()
463
        if parent_ids:
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
464
            return parent_ids[0]
2255.2.21 by Robert Collins
Add WorkingTree4._last_revision, making workingtree_implementations.test_changes_from pass.
465
        else:
466
            return None
467
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
468
    def lock_read(self):
469
        super(WorkingTree4, self).lock_read()
470
        if self._dirstate is None:
471
            self.current_dirstate()
472
            self._dirstate.lock_read()
473
474
    def lock_tree_write(self):
475
        super(WorkingTree4, self).lock_tree_write()
476
        if self._dirstate is None:
477
            self.current_dirstate()
478
            self._dirstate.lock_write()
479
480
    def lock_write(self):
481
        super(WorkingTree4, self).lock_write()
482
        if self._dirstate is None:
483
            self.current_dirstate()
484
            self._dirstate.lock_write()
485
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
486
    @needs_tree_write_lock
2255.2.137 by John Arbash Meinel
Move the WorkingTree.move() tests into their own module
487
    def move(self, from_paths, to_dir, after=False):
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
488
        """See WorkingTree.move()."""
489
        if not from_paths:
490
            return ()
491
492
        state = self.current_dirstate()
493
494
        assert not isinstance(from_paths, basestring)
495
        to_dir_utf8 = to_dir.encode('utf8')
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
496
        to_entry_dirname, to_basename = os.path.split(to_dir_utf8)
2255.2.146 by John Arbash Meinel
Implement move_directory by factoring out move_one
497
        id_index = state._get_id_index()
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
498
        # check destination directory
499
        # get the details for it
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
500
        to_entry_block_index, to_entry_entry_index, dir_present, entry_present = \
501
            state._get_block_entry_index(to_entry_dirname, to_basename, 0)
502
        if not entry_present:
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
503
            raise errors.BzrMoveFailedError('', to_dir,
504
                errors.NotInWorkingDirectory(to_dir))
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
505
        to_entry = state._dirblocks[to_entry_block_index][1][to_entry_entry_index]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
506
        # get a handle on the block itself.
507
        to_block_index = state._ensure_block(
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
508
            to_entry_block_index, to_entry_entry_index, to_dir_utf8)
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
509
        to_block = state._dirblocks[to_block_index]
510
        to_abs = self.abspath(to_dir)
511
        if not isdir(to_abs):
512
            raise errors.BzrMoveFailedError('',to_dir,
513
                errors.NotADirectory(to_abs))
514
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
515
        if to_entry[1][0][0] != 'd':
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
516
            raise errors.BzrMoveFailedError('',to_dir,
517
                errors.NotADirectory(to_abs))
518
519
        if self._inventory is not None:
520
            update_inventory = True
521
            inv = self.inventory
522
            to_dir_ie = inv[to_dir_id]
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
523
            to_dir_id = to_entry[0][2]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
524
        else:
525
            update_inventory = False
526
2255.2.146 by John Arbash Meinel
Implement move_directory by factoring out move_one
527
        rollbacks = []
528
        def move_one(old_entry, from_path_utf8, minikind, executable,
529
                     fingerprint, packed_stat, size,
530
                     to_block, to_key, to_path_utf8):
531
            state._make_absent(old_entry)
532
            from_key = old_entry[0]
533
            rollbacks.append(
534
                lambda:state.update_minimal(from_key,
535
                    minikind,
536
                    executable=executable,
537
                    fingerprint=fingerprint,
538
                    packed_stat=packed_stat,
539
                    size=size,
540
                    path_utf8=from_path_utf8))
541
            state.update_minimal(to_key,
542
                    minikind,
543
                    executable=executable,
544
                    fingerprint=fingerprint,
545
                    packed_stat=packed_stat,
546
                    size=size,
547
                    path_utf8=to_path_utf8)
548
            added_entry_index, _ = state._find_entry_index(to_key, to_block[1])
549
            new_entry = to_block[1][added_entry_index]
550
            rollbacks.append(lambda:state._make_absent(new_entry))
551
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
552
        # create rename entries and tuples
553
        for from_rel in from_paths:
554
            # from_rel is 'pathinroot/foo/bar'
2255.2.146 by John Arbash Meinel
Implement move_directory by factoring out move_one
555
            from_rel_utf8 = from_rel.encode('utf8')
556
            from_dirname, from_tail = osutils.split(from_rel)
557
            from_dirname, from_tail_utf8 = osutils.split(from_rel_utf8)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
558
            from_entry = self._get_entry(path=from_rel)
559
            if from_entry == (None, None):
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
560
                raise errors.BzrMoveFailedError(from_rel,to_dir,
561
                    errors.NotVersionedError(path=str(from_rel)))
562
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
563
            from_id = from_entry[0][2]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
564
            to_rel = pathjoin(to_dir, from_tail)
2255.2.146 by John Arbash Meinel
Implement move_directory by factoring out move_one
565
            to_rel_utf8 = pathjoin(to_dir_utf8, from_tail_utf8)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
566
            item_to_entry = self._get_entry(path=to_rel)
567
            if item_to_entry != (None, None):
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
568
                raise errors.BzrMoveFailedError(from_rel, to_rel,
569
                    "Target is already versioned.")
570
571
            if from_rel == to_rel:
572
                raise errors.BzrMoveFailedError(from_rel, to_rel,
573
                    "Source and target are identical.")
574
575
            from_missing = not self.has_filename(from_rel)
576
            to_missing = not self.has_filename(to_rel)
577
            if after:
578
                move_file = False
579
            else:
580
                move_file = True
581
            if to_missing:
582
                if not move_file:
583
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
584
                        errors.NoSuchFile(path=to_rel,
585
                        extra="New file has not been created yet"))
586
                elif from_missing:
587
                    # neither path exists
588
                    raise errors.BzrRenameFailedError(from_rel, to_rel,
589
                        errors.PathsDoNotExist(paths=(from_rel, to_rel)))
590
            else:
591
                if from_missing: # implicitly just update our path mapping
592
                    move_file = False
2255.2.139 by John Arbash Meinel
test cases for moving after a file has already been moved.
593
                elif not after:
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
594
                    raise errors.RenameFailedFilesExist(from_rel, to_rel,
595
                        extra="(Use --after to update the Bazaar id)")
596
597
            rollbacks = []
598
            def rollback_rename():
599
                """A single rename has failed, roll it back."""
2255.2.138 by John Arbash Meinel
implement several new WorkingTree.move() tests
600
                exc_info = None
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
601
                for rollback in reversed(rollbacks):
602
                    try:
603
                        rollback()
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
604
                    except Exception, e:
605
                        import pdb;pdb.set_trace()
2255.2.138 by John Arbash Meinel
implement several new WorkingTree.move() tests
606
                        exc_info = sys.exc_info()
607
                if exc_info:
608
                    raise exc_info[0], exc_info[1], exc_info[2]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
609
610
            # perform the disk move first - its the most likely failure point.
2255.2.139 by John Arbash Meinel
test cases for moving after a file has already been moved.
611
            if move_file:
612
                from_rel_abs = self.abspath(from_rel)
613
                to_rel_abs = self.abspath(to_rel)
614
                try:
615
                    osutils.rename(from_rel_abs, to_rel_abs)
616
                except OSError, e:
617
                    raise errors.BzrMoveFailedError(from_rel, to_rel, e[1])
2255.2.140 by John Arbash Meinel
Update tests to ensure basis tree is not modified
618
                rollbacks.append(lambda: osutils.rename(to_rel_abs, from_rel_abs))
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
619
            try:
620
                # perform the rename in the inventory next if needed: its easy
621
                # to rollback
622
                if update_inventory:
623
                    # rename the entry
624
                    from_entry = inv[from_id]
625
                    current_parent = from_entry.parent_id
626
                    inv.rename(from_id, to_dir_id, from_tail)
627
                    rollbacks.append(
628
                        lambda: inv.rename(from_id, current_parent, from_tail))
629
                # finally do the rename in the dirstate, which is a little
630
                # tricky to rollback, but least likely to need it.
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
631
                old_block_index, old_entry_index, dir_present, file_present = \
2255.2.146 by John Arbash Meinel
Implement move_directory by factoring out move_one
632
                    state._get_block_entry_index(from_dirname, from_tail_utf8, 0)
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
633
                old_block = state._dirblocks[old_block_index][1]
2255.2.146 by John Arbash Meinel
Implement move_directory by factoring out move_one
634
                old_entry = old_block[old_entry_index]
635
                from_key, old_entry_details = old_entry
636
                cur_details = old_entry_details[0]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
637
                # remove the old row
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
638
                to_key = ((to_block[0],) + from_key[1:3])
2255.2.146 by John Arbash Meinel
Implement move_directory by factoring out move_one
639
                minikind = cur_details[0]
640
                move_one(old_entry, from_path_utf8=from_rel_utf8,
641
                         minikind=minikind,
642
                         executable=cur_details[3],
643
                         fingerprint=cur_details[1],
644
                         packed_stat=cur_details[4],
645
                         size=cur_details[2],
646
                         to_block=to_block,
647
                         to_key=to_key,
648
                         to_path_utf8=to_rel_utf8)
649
650
                if minikind == 'd':
651
                    def update_dirblock(from_dir, to_key, to_dir_utf8):
652
                        """all entries in this block need updating.
653
654
                        TODO: This is pretty ugly, and doesn't support
655
                        reverting, but it works.
656
                        """
657
                        assert from_dir != '', "renaming root not supported"
658
                        from_key = (from_dir, '')
659
                        from_block_idx, present = \
660
                            state._find_block_index_from_key(from_key)
661
                        if not present:
662
                            # This is the old record, if it isn't present, then
663
                            # there is theoretically nothing to update.
664
                            # (Unless it isn't present because of lazy loading,
665
                            # but we don't do that yet)
666
                            return
667
                        from_block = state._dirblocks[from_block_idx]
668
                        to_block_index, to_entry_index, _, _ = \
669
                            state._get_block_entry_index(to_key[0], to_key[1], 0)
670
                        to_block_index = state._ensure_block(
671
                            to_block_index, to_entry_index, to_dir_utf8)
672
                        to_block = state._dirblocks[to_block_index]
673
                        for entry in from_block[1]:
674
                            assert entry[0][0] == from_dir
675
                            cur_details = entry[1][0]
676
                            to_key = (to_dir_utf8, entry[0][1], entry[0][2])
677
                            from_path_utf8 = osutils.pathjoin(entry[0][0], entry[0][1])
678
                            to_path_utf8 = osutils.pathjoin(to_dir_utf8, entry[0][1])
679
                            minikind = cur_details[0]
680
                            move_one(entry, from_path_utf8=from_path_utf8,
681
                                     minikind=minikind,
682
                                     executable=cur_details[3],
683
                                     fingerprint=cur_details[1],
684
                                     packed_stat=cur_details[4],
685
                                     size=cur_details[2],
686
                                     to_block=to_block,
687
                                     to_key=to_key,
688
                                     to_path_utf8=to_rel_utf8)
689
                            if minikind == 'd':
690
                                # We need to move all the children of this
691
                                # entry
692
                                update_dirblock(from_path_utf8, to_key,
693
                                                to_path_utf8)
694
                    update_dirblock(from_rel_utf8, to_key, to_rel_utf8)
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
695
            except:
696
                rollback_rename()
697
                raise
698
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
699
            self._dirty = True
700
701
        return #rename_tuples
702
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
703
    def _must_be_locked(self):
704
        if not self._control_files._lock_count:
705
            raise errors.ObjectNotLocked(self)
706
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
707
    def _new_tree(self):
708
        """Initialize the state in this tree to be a new tree."""
709
        self._dirty = True
710
711
    @needs_read_lock
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
712
    def path2id(self, path):
713
        """Return the id for path in this tree."""
2255.2.88 by Robert Collins
Significant steps back to operation.
714
        entry = self._get_entry(path=path)
715
        if entry == (None, None):
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
716
            return None
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
717
        return entry[0][2]
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
718
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
719
    def paths2ids(self, paths, trees=[], require_versioned=True):
720
        """See Tree.paths2ids().
2255.7.24 by John Arbash Meinel
Rework cmd_inventory so that it uses paths2ids and locks the trees for read.
721
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
722
        This specialisation fast-paths the case where all the trees are in the
723
        dirstate.
724
        """
725
        if paths is None:
726
            return None
727
        parents = self.get_parent_ids()
728
        for tree in trees:
729
            if not (isinstance(tree, DirStateRevisionTree) and tree._revision_id in
730
                parents):
731
                return super(WorkingTree4, self).paths2ids(paths, trees, require_versioned)
732
        search_indexes = [0] + [1 + parents.index(tree._revision_id) for tree in trees]
733
        # -- make all paths utf8 --
734
        paths_utf8 = set()
735
        for path in paths:
736
            paths_utf8.add(path.encode('utf8'))
737
        paths = paths_utf8
738
        # -- paths is now a utf8 path set --
739
        # -- get the state object and prepare it.
740
        state = self.current_dirstate()
2255.2.133 by John Arbash Meinel
Implement _paths2ids using bisect recursive rather than loading
741
        if False and (state._dirblock_state == dirstate.DirState.NOT_IN_MEMORY
742
            and '' not in paths):
743
            paths2ids = self._paths2ids_using_bisect
744
        else:
745
            paths2ids = self._paths2ids_in_memory
746
        return paths2ids(paths, search_indexes,
747
                         require_versioned=require_versioned)
748
749
    def _paths2ids_in_memory(self, paths, search_indexes,
750
                             require_versioned=True):
751
        state = self.current_dirstate()
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
752
        state._read_dirblocks_if_needed()
753
        def _entries_for_path(path):
754
            """Return a list with all the entries that match path for all ids.
755
            """
756
            dirname, basename = os.path.split(path)
757
            key = (dirname, basename, '')
758
            block_index, present = state._find_block_index_from_key(key)
759
            if not present:
760
                # the block which should contain path is absent.
761
                return []
762
            result = []
763
            block = state._dirblocks[block_index][1]
764
            entry_index, _ = state._find_entry_index(key, block)
765
            # we may need to look at multiple entries at this path: walk while the paths match.
766
            while (entry_index < len(block) and
767
                block[entry_index][0][0:2] == key[0:2]):
768
                result.append(block[entry_index])
769
                entry_index += 1
770
            return result
771
        if require_versioned:
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
772
            # -- check all supplied paths are versioned in a search tree. --
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
773
            all_versioned = True
774
            for path in paths:
775
                path_entries = _entries_for_path(path)
776
                if not path_entries:
777
                    # this specified path is not present at all: error
778
                    all_versioned = False
779
                    break
780
                found_versioned = False
781
                # for each id at this path
782
                for entry in path_entries:
783
                    # for each tree.
784
                    for index in search_indexes:
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
785
                        if entry[1][index][0] != 'a': # absent
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
786
                            found_versioned = True
787
                            # all good: found a versioned cell
788
                            break
789
                if not found_versioned:
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
790
                    # none of the indexes was not 'absent' at all ids for this
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
791
                    # path.
792
                    all_versioned = False
793
                    break
794
            if not all_versioned:
795
                raise errors.PathsNotVersionedError(paths)
796
        # -- remove redundancy in supplied paths to prevent over-scanning --
797
        search_paths = set()
798
        for path in paths:
799
            other_paths = paths.difference(set([path]))
800
            if not osutils.is_inside_any(other_paths, path):
801
                # this is a top level path, we must check it.
802
                search_paths.add(path)
803
        # sketch: 
804
        # for all search_indexs in each path at or under each element of
805
        # search_paths, if the detail is relocated: add the id, and add the
806
        # relocated path as one to search if its not searched already. If the
807
        # detail is not relocated, add the id.
808
        searched_paths = set()
809
        found_ids = set()
810
        def _process_entry(entry):
811
            """Look at search_indexes within entry.
812
813
            If a specific tree's details are relocated, add the relocation
814
            target to search_paths if not searched already. If it is absent, do
815
            nothing. Otherwise add the id to found_ids.
816
            """
817
            for index in search_indexes:
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
818
                if entry[1][index][0] == 'r': # relocated
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
819
                    if not osutils.is_inside_any(searched_paths, entry[1][index][1]):
820
                        search_paths.add(entry[1][index][1])
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
821
                elif entry[1][index][0] != 'a': # absent
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
822
                    found_ids.add(entry[0][2])
823
        while search_paths:
824
            current_root = search_paths.pop()
825
            searched_paths.add(current_root)
826
            # process the entries for this containing directory: the rest will be
827
            # found by their parents recursively.
828
            root_entries = _entries_for_path(current_root)
829
            if not root_entries:
830
                # this specified path is not present at all, skip it.
831
                continue
832
            for entry in root_entries:
833
                _process_entry(entry)
834
            initial_key = (current_root, '', '')
835
            block_index, _ = state._find_block_index_from_key(initial_key)
836
            while (block_index < len(state._dirblocks) and
837
                osutils.is_inside(current_root, state._dirblocks[block_index][0])):
838
                for entry in state._dirblocks[block_index][1]:
839
                    _process_entry(entry)
840
                block_index += 1
841
        return found_ids
842
2255.2.133 by John Arbash Meinel
Implement _paths2ids using bisect recursive rather than loading
843
    def _paths2ids_using_bisect(self, paths, search_indexes,
844
                                require_versioned=True):
845
        state = self.current_dirstate()
846
        found_ids = set()
847
848
        split_paths = sorted(osutils.split(p) for p in paths)
849
        found = state._bisect_recursive(split_paths)
850
851
        if require_versioned:
852
            found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
853
            for dir_name in split_paths:
854
                if dir_name not in found_dir_names:
855
                    raise errors.PathsNotVersionedError(paths)
856
857
        for dir_name_id, trees_info in found.iteritems():
858
            for index in search_indexes:
859
                if trees_info[index][0] not in ('r', 'a'):
860
                    found_ids.add(dir_name_id[2])
861
        return found_ids
862
2255.2.45 by Robert Collins
Dirstate - fix revision_tree() behaviour to match the interface contract.
863
    def read_working_inventory(self):
864
        """Read the working inventory.
865
        
866
        This is a meaningless operation for dirstate, but we obey it anyhow.
867
        """
868
        return self.inventory
869
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
870
    @needs_read_lock
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
871
    def revision_tree(self, revision_id):
872
        """See Tree.revision_tree.
873
874
        WorkingTree4 supplies revision_trees for any basis tree.
875
        """
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
876
        revision_id = osutils.safe_revision_id(revision_id)
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
877
        dirstate = self.current_dirstate()
878
        parent_ids = dirstate.get_parent_ids()
879
        if revision_id not in parent_ids:
880
            raise errors.NoSuchRevisionInTree(self, revision_id)
2255.2.45 by Robert Collins
Dirstate - fix revision_tree() behaviour to match the interface contract.
881
        if revision_id in dirstate.get_ghosts():
882
            raise errors.NoSuchRevisionInTree(self, revision_id)
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
883
        return DirStateRevisionTree(dirstate, revision_id,
884
            self.branch.repository)
885
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
886
    @needs_tree_write_lock
2255.2.37 by Robert Collins
Get TestExecutable.test_06_pull working on DirState: fix cloning and the set_last_revision api on WorkingTree4.
887
    def set_last_revision(self, new_revision):
888
        """Change the last revision in the working tree."""
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
889
        new_revision = osutils.safe_revision_id(new_revision)
2255.2.37 by Robert Collins
Get TestExecutable.test_06_pull working on DirState: fix cloning and the set_last_revision api on WorkingTree4.
890
        parents = self.get_parent_ids()
891
        if new_revision in (NULL_REVISION, None):
2255.2.56 by Robert Collins
Dirstate: bring set_last_revision into line with the tested API.
892
            assert len(parents) < 2, (
2255.2.37 by Robert Collins
Get TestExecutable.test_06_pull working on DirState: fix cloning and the set_last_revision api on WorkingTree4.
893
                "setting the last parent to none with a pending merge is "
894
                "unsupported.")
895
            self.set_parent_ids([])
896
        else:
2255.2.56 by Robert Collins
Dirstate: bring set_last_revision into line with the tested API.
897
            self.set_parent_ids([new_revision] + parents[1:],
898
                allow_leftmost_as_ghost=True)
2255.2.37 by Robert Collins
Get TestExecutable.test_06_pull working on DirState: fix cloning and the set_last_revision api on WorkingTree4.
899
900
    @needs_tree_write_lock
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
901
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
902
        """Set the parent ids to revision_ids.
903
        
904
        See also set_parent_trees. This api will try to retrieve the tree data
905
        for each element of revision_ids from the trees repository. If you have
906
        tree data already available, it is more efficient to use
907
        set_parent_trees rather than set_parent_ids. set_parent_ids is however
908
        an easier API to use.
909
910
        :param revision_ids: The revision_ids to set as the parent ids of this
911
            working tree. Any of these may be ghosts.
912
        """
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
913
        revision_ids = [osutils.safe_revision_id(r) for r in revision_ids]
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
914
        trees = []
915
        for revision_id in revision_ids:
916
            try:
917
                revtree = self.branch.repository.revision_tree(revision_id)
2255.2.24 by John Arbash Meinel
When adding ghosts revision_tree() raises RevisionNotPresent because of Knit, not NoSuchRevision
918
                # TODO: jam 20070213 KnitVersionedFile raises
919
                #       RevisionNotPresent rather than NoSuchRevision if a
920
                #       given revision_id is not present. Should Repository be
921
                #       catching it and re-raising NoSuchRevision?
922
            except (errors.NoSuchRevision, errors.RevisionNotPresent):
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
923
                revtree = None
924
            trees.append((revision_id, revtree))
925
        self.set_parent_trees(trees,
926
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
927
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
928
    @needs_tree_write_lock
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
929
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
930
        """Set the parents of the working tree.
931
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
932
        :param parents_list: A list of (revision_id, tree) tuples.
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
933
            If tree is None, then that element is treated as an unreachable
934
            parent tree - i.e. a ghost.
935
        """
936
        dirstate = self.current_dirstate()
937
        if len(parents_list) > 0:
938
            if not allow_leftmost_as_ghost and parents_list[0][1] is None:
2255.2.42 by Robert Collins
Fix WorkingTree4.set_parent_trees.
939
                raise errors.GhostRevisionUnusableHere(parents_list[0][0])
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
940
        real_trees = []
941
        ghosts = []
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
942
        # convert absent trees to the null tree, which we convert back to
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
943
        # missing on access.
944
        for rev_id, tree in parents_list:
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
945
            rev_id = osutils.safe_revision_id(rev_id)
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
946
            if tree is not None:
947
                real_trees.append((rev_id, tree))
948
            else:
949
                real_trees.append((rev_id,
950
                    self.branch.repository.revision_tree(None)))
951
                ghosts.append(rev_id)
952
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
953
        self._dirty = True
954
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
955
    def _set_root_id(self, file_id):
956
        """See WorkingTree.set_root_id."""
2255.2.37 by Robert Collins
Get TestExecutable.test_06_pull working on DirState: fix cloning and the set_last_revision api on WorkingTree4.
957
        state = self.current_dirstate()
958
        state.set_path_id('', file_id)
959
        self._dirty = state._dirblock_state == dirstate.DirState.IN_MEMORY_MODIFIED
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
960
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
961
    def unlock(self):
962
        """Unlock in format 4 trees needs to write the entire dirstate."""
963
        if self._control_files._lock_count == 1:
2255.2.44 by Robert Collins
Fix tree unlock on readonly Format4 trees with dirty hashcache.
964
            self._write_hashcache_if_dirty()
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
965
            # eventually we should do signature checking during read locks for
966
            # dirstate updates.
967
            if self._control_files._lock_mode == 'w':
968
                if self._dirty:
969
                    self.flush()
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
970
            if self._dirstate is not None:
971
                self._dirstate.unlock()
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
972
            self._dirstate = None
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
973
            self._inventory = None
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
974
        # reverse order of locking.
975
        try:
976
            return self._control_files.unlock()
977
        finally:
978
            self.branch.unlock()
979
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
980
    @needs_tree_write_lock
981
    def unversion(self, file_ids):
982
        """Remove the file ids in file_ids from the current versioned set.
983
984
        When a file_id is unversioned, all of its children are automatically
985
        unversioned.
986
987
        :param file_ids: The file ids to stop versioning.
988
        :raises: NoSuchId if any fileid is not currently versioned.
989
        """
990
        if not file_ids:
991
            return
992
        state = self.current_dirstate()
993
        state._read_dirblocks_if_needed()
994
        ids_to_unversion = set()
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
995
        for file_id in file_ids:
996
            ids_to_unversion.add(osutils.safe_file_id(file_id))
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
997
        paths_to_unversion = set()
998
        # sketch:
999
        # check if the root is to be unversioned, if so, assert for now.
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1000
        # walk the state marking unversioned things as absent.
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
1001
        # if there are any un-unversioned ids at the end, raise
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1002
        for key, details in state._dirblocks[0][1]:
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1003
            if (details[0][0] not in ('a', 'r') and # absent or relocated
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1004
                key[2] in ids_to_unversion):
1005
                # I haven't written the code to unversion / yet - it should be
1006
                # supported.
1007
                raise errors.BzrError('Unversioning the / is not currently supported')
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1008
        details_length = len(state._dirblocks[0][1][0][1])
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1009
        block_index = 0
1010
        while block_index < len(state._dirblocks):
1011
            # process one directory at a time.
1012
            block = state._dirblocks[block_index]
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
1013
            # first check: is the path one to remove - it or its children
1014
            delete_block = False
1015
            for path in paths_to_unversion:
1016
                if (block[0].startswith(path) and
1017
                    (len(block[0]) == len(path) or
1018
                     block[0][len(path)] == '/')):
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1019
                    # this entire block should be deleted - its the block for a
1020
                    # path to unversion; or the child of one
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
1021
                    delete_block = True
1022
                    break
1023
            # TODO: trim paths_to_unversion as we pass by paths
1024
            if delete_block:
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1025
                # this block is to be deleted: process it.
1026
                # TODO: we can special case the no-parents case and
1027
                # just forget the whole block.
1028
                entry_index = 0
1029
                while entry_index < len(block[1]):
1030
                    if not state._make_absent(block[1][entry_index]):
1031
                        entry_index += 1
1032
                # go to the next block. (At the moment we dont delete empty
1033
                # dirblocks)
1034
                block_index += 1
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
1035
                continue
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1036
            entry_index = 0
1037
            while entry_index < len(block[1]):
1038
                entry = block[1][entry_index]
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1039
                if (entry[1][0][0] in ('a', 'r') or # absent, relocated
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1040
                    # ^ some parent row.
1041
                    entry[0][2] not in ids_to_unversion):
1042
                    # ^ not an id to unversion
1043
                    entry_index += 1
1044
                    continue
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1045
                if entry[1][0][0] == 'd':
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1046
                    paths_to_unversion.add(os.path.join(*entry[0][0:2]))
1047
                if not state._make_absent(entry):
1048
                    entry_index += 1
1049
                # we have unversioned this id
1050
                ids_to_unversion.remove(entry[0][2])
1051
            block_index += 1
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
1052
        if ids_to_unversion:
1053
            raise errors.NoSuchId(self, iter(ids_to_unversion).next())
2255.2.46 by Robert Collins
Dirstate - unversion should set the tree state as dirty.
1054
        self._dirty = True
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
1055
        # have to change the legacy inventory too.
1056
        if self._inventory is not None:
1057
            for file_id in file_ids:
2255.2.33 by Robert Collins
Correct thunko in refactoring a few commits back.
1058
                self._inventory.remove_recursive_id(file_id)
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
1059
2255.2.16 by Robert Collins
Implement WorkingTreeFormat4._write_inventory for better compatability with existing code, letting more test_test_trees pass, now up to test_tree_with_subdirs_and_all_content_types.
1060
    @needs_tree_write_lock
1061
    def _write_inventory(self, inv):
1062
        """Write inventory as the current inventory."""
1063
        assert not self._dirty, "attempting to write an inventory when the dirstate is dirty will cause data loss"
1064
        self.current_dirstate().set_state_from_inventory(inv)
1065
        self._dirty = True
1066
        self.flush()
1067
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1068
1069
class WorkingTreeFormat4(WorkingTreeFormat3):
1070
    """The first consolidated dirstate working tree format.
1071
1072
    This format:
1073
        - exists within a metadir controlling .bzr
1074
        - includes an explicit version marker for the workingtree control
1075
          files, separate from the BzrDir format
1076
        - modifies the hash cache format
1077
        - is new in bzr TODO FIXME SETBEFOREMERGE
1078
        - uses a LockDir to guard access to it.
1079
    """
1080
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
1081
    supports_tree_reference = True
1082
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1083
    def get_format_string(self):
1084
        """See WorkingTreeFormat.get_format_string()."""
1085
        return "Bazaar Working Tree format 4\n"
1086
1087
    def get_format_description(self):
1088
        """See WorkingTreeFormat.get_format_description()."""
1089
        return "Working tree format 4"
1090
1091
    def initialize(self, a_bzrdir, revision_id=None):
1092
        """See WorkingTreeFormat.initialize().
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1093
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1094
        revision_id allows creating a working tree at a different
1095
        revision than the branch is at.
1096
        """
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1097
        revision_id = osutils.safe_revision_id(revision_id)
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1098
        if not isinstance(a_bzrdir.transport, LocalTransport):
1099
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1100
        transport = a_bzrdir.get_workingtree_transport(self)
1101
        control_files = self._open_control_files(a_bzrdir)
1102
        control_files.create_lock()
1103
        control_files.lock_write()
1104
        control_files.put_utf8('format', self.get_format_string())
1105
        branch = a_bzrdir.open_branch()
1106
        if revision_id is None:
1107
            revision_id = branch.last_revision()
1108
        local_path = transport.local_abspath('dirstate')
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
1109
        state = dirstate.DirState.initialize(local_path)
1110
        state.unlock()
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1111
        wt = WorkingTree4(a_bzrdir.root_transport.local_abspath('.'),
1112
                         branch,
1113
                         _format=self,
1114
                         _bzrdir=a_bzrdir,
1115
                         _control_files=control_files)
1116
        wt._new_tree()
1117
        wt.lock_write()
1118
        try:
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
1119
            #wt.current_dirstate().set_path_id('', NEWROOT)
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1120
            wt.set_last_revision(revision_id)
2255.2.16 by Robert Collins
Implement WorkingTreeFormat4._write_inventory for better compatability with existing code, letting more test_test_trees pass, now up to test_tree_with_subdirs_and_all_content_types.
1121
            wt.flush()
2255.2.37 by Robert Collins
Get TestExecutable.test_06_pull working on DirState: fix cloning and the set_last_revision api on WorkingTree4.
1122
            basis = wt.basis_tree()
1123
            basis.lock_read()
1124
            transform.build_tree(basis, wt)
1125
            basis.unlock()
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1126
        finally:
1127
            control_files.unlock()
1128
            wt.unlock()
1129
        return wt
1130
1131
    def _open(self, a_bzrdir, control_files):
1132
        """Open the tree itself.
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1133
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1134
        :param a_bzrdir: the dir for the tree.
1135
        :param control_files: the control files for the tree.
1136
        """
1137
        return WorkingTree4(a_bzrdir.root_transport.local_abspath('.'),
1138
                           branch=a_bzrdir.open_branch(),
1139
                           _format=self,
1140
                           _bzrdir=a_bzrdir,
1141
                           _control_files=control_files)
1142
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
1143
    def __get_matchingbzrdir(self):
1144
        # please test against something that will let us do tree references
1145
        return bzrdir.format_registry.make_bzrdir(
1146
            'experimental-reference-dirstate')
1147
1148
    _matchingbzrdir = property(__get_matchingbzrdir)
1149
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1150
1151
class DirStateRevisionTree(Tree):
1152
    """A revision tree pulling the inventory from a dirstate."""
1153
1154
    def __init__(self, dirstate, revision_id, repository):
1155
        self._dirstate = dirstate
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1156
        self._revision_id = osutils.safe_revision_id(revision_id)
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1157
        self._repository = repository
1158
        self._inventory = None
2255.2.38 by Robert Collins
Fix WorkingTree4.pull to work.
1159
        self._locked = 0
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
1160
        self._dirstate_locked = False
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1161
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1162
    def annotate_iter(self, file_id):
1163
        """See Tree.annotate_iter"""
1164
        w = self._repository.weave_store.get_weave(file_id,
1165
                           self._repository.get_transaction())
1166
        return w.annotate_iter(self.inventory[file_id].revision)
1167
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1168
    def _comparison_data(self, entry, path):
1169
        if entry is None:
1170
            return None, False, None
1171
        # trust the entry as RevisionTree does, but this may not be
1172
        # sensible: the entry might not have come from us?
1173
        return entry.kind, entry.executable, None
1174
2255.2.10 by Robert Collins
Now all tests matching dirstate pass - added generation of inventories for parent trees.
1175
    def _file_size(self, entry, stat_value):
1176
        return entry.text_size
1177
2255.2.78 by Robert Collins
Really finish the prior commit.
1178
    def filter_unversioned_files(self, paths):
1179
        """Filter out paths that are not versioned.
1180
1181
        :return: set of paths.
1182
        """
1183
        pred = self.has_filename
1184
        return set((p for p in paths if not pred(p)))
1185
2255.2.134 by John Arbash Meinel
Add a tree-test for get_symlink_target
1186
    def _get_parent_index(self):
1187
        """Return the index in the dirstate referenced by this tree."""
1188
        return self._dirstate.get_parent_ids().index(self._revision_id) + 1
1189
2255.2.98 by Robert Collins
Perform path2id lookups in dirstate revision trees from the dirstate index without requiring an inventory.
1190
    def _get_entry(self, file_id=None, path=None):
1191
        """Get the dirstate row for file_id or path.
1192
1193
        If either file_id or path is supplied, it is used as the key to lookup.
1194
        If both are supplied, the fastest lookup is used, and an error is
1195
        raised if they do not both point at the same row.
1196
        
1197
        :param file_id: An optional unicode file_id to be looked up.
1198
        :param path: An optional unicode path to be looked up.
1199
        :return: The dirstate row tuple for path/file_id, or (None, None)
1200
        """
1201
        if file_id is None and path is None:
1202
            raise errors.BzrError('must supply file_id or path')
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1203
        file_id = osutils.safe_file_id(file_id)
2255.2.98 by Robert Collins
Perform path2id lookups in dirstate revision trees from the dirstate index without requiring an inventory.
1204
        if path is not None:
1205
            path = path.encode('utf8')
2255.2.134 by John Arbash Meinel
Add a tree-test for get_symlink_target
1206
        parent_index = self._get_parent_index()
2255.2.98 by Robert Collins
Perform path2id lookups in dirstate revision trees from the dirstate index without requiring an inventory.
1207
        return self._dirstate._get_entry(parent_index, fileid_utf8=file_id, path_utf8=path)
1208
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1209
    def _generate_inventory(self):
1210
        """Create and set self.inventory from the dirstate object.
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1211
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
1212
        (So this is only called the first time the inventory is requested for
1213
        this tree; it then remains in memory.)
1214
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1215
        This is relatively expensive: we have to walk the entire dirstate.
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
1216
        """
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1217
        assert self._locked, 'cannot generate inventory of an unlocked '\
1218
            'dirstate revision tree'
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1219
        # separate call for profiling - makes it clear where the costs are.
1220
        self._dirstate._read_dirblocks_if_needed()
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1221
        assert self._revision_id in self._dirstate.get_parent_ids(), \
1222
            'parent %s has disappeared from %s' % (
1223
            self._revision_id, self._dirstate.get_parent_ids())
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1224
        parent_index = self._dirstate.get_parent_ids().index(self._revision_id) + 1
1225
        # This is identical now to the WorkingTree _generate_inventory except
1226
        # for the tree index use.
1227
        root_key, current_entry = self._dirstate._get_entry(parent_index, path_utf8='')
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1228
        current_id = root_key[2]
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1229
        assert current_entry[parent_index][0] == 'd'
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1230
        inv = Inventory(root_id=current_id, revision_id=self._revision_id)
1231
        inv.root.revision = current_entry[parent_index][4]
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
1232
        # Turn some things into local variables
1233
        minikind_to_kind = dirstate.DirState._minikind_to_kind
1234
        factory = entry_factory
1235
        utf8_decode = cache_utf8._utf8_decode
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1236
        inv_byid = inv._byid
2255.2.73 by Robert Collins
50% speedup in the dirstate->inventory conversion logic by caching the parent ids as we walk the tree. Some further work would be to maintain a stack of parents as we know we visit depth first.
1237
        # we could do this straight out of the dirstate; it might be fast
1238
        # and should be profiled - RBC 20070216
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1239
        parent_ies = {'' : inv.root}
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1240
        for block in self._dirstate._dirblocks[1:]: #skip root
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1241
            dirname = block[0]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1242
            try:
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1243
                parent_ie = parent_ies[dirname]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1244
            except KeyError:
1245
                # all the paths in this block are not versioned in this tree
1246
                continue
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1247
            for key, entry in block[1]:
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
1248
                minikind, fingerprint, size, executable, revid = entry[parent_index]
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
1249
                if minikind in ('a', 'r'): # absent, relocated
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1250
                    # not this tree
1251
                    continue
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1252
                name = key[1]
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
1253
                name_unicode = utf8_decode(name)[0]
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1254
                file_id = key[2]
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
1255
                kind = minikind_to_kind[minikind]
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1256
                inv_entry = factory[kind](file_id, name_unicode,
1257
                                          parent_ie.file_id)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1258
                inv_entry.revision = revid
1259
                if kind == 'file':
1260
                    inv_entry.executable = executable
1261
                    inv_entry.text_size = size
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
1262
                    inv_entry.text_sha1 = fingerprint
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1263
                elif kind == 'directory':
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1264
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1265
                elif kind == 'symlink':
1266
                    inv_entry.executable = False
1267
                    inv_entry.text_size = size
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
1268
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1269
                elif kind == 'tree-reference':
1270
                    inv_entry.reference_revision = fingerprint
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1271
                else:
2255.2.158 by Martin Pool
Most of the integration of dirstate and subtree
1272
                    raise AssertionError("cannot convert entry %r into an InventoryEntry"
1273
                            % entry)
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1274
                # These checks cost us around 40ms on a 55k entry tree
1275
                assert file_id not in inv_byid
1276
                assert name_unicode not in parent_ie.children
1277
                inv_byid[file_id] = inv_entry
1278
                parent_ie.children[name_unicode] = inv_entry
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1279
        self._inventory = inv
1280
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1281
    def get_file_sha1(self, file_id, path=None, stat_value=None):
1282
        # TODO: if path is present, fast-path on that, as inventory
1283
        # might not be present
1284
        ie = self.inventory[file_id]
1285
        if ie.kind == "file":
1286
            return ie.text_sha1
1287
        return None
1288
1289
    def get_file(self, file_id):
1290
        return StringIO(self.get_file_text(file_id))
1291
1292
    def get_file_lines(self, file_id):
1293
        ie = self.inventory[file_id]
1294
        return self._repository.weave_store.get_weave(file_id,
1295
                self._repository.get_transaction()).get_lines(ie.revision)
1296
1297
    def get_file_size(self, file_id):
1298
        return self.inventory[file_id].text_size
1299
1300
    def get_file_text(self, file_id):
1301
        return ''.join(self.get_file_lines(file_id))
1302
2255.2.134 by John Arbash Meinel
Add a tree-test for get_symlink_target
1303
    def get_symlink_target(self, file_id):
1304
        entry = self._get_entry(file_id=file_id)
1305
        parent_index = self._get_parent_index()
1306
        if entry[1][parent_index][0] != 'l':
1307
            return None
1308
        else:
1309
            # At present, none of the tree implementations supports non-ascii
1310
            # symlink targets. So we will just assume that the dirstate path is
1311
            # correct.
1312
            return entry[1][parent_index][1]
1313
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1314
    def get_revision_id(self):
1315
        """Return the revision id for this tree."""
1316
        return self._revision_id
1317
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1318
    def _get_inventory(self):
1319
        if self._inventory is not None:
1320
            return self._inventory
1321
        self._generate_inventory()
1322
        return self._inventory
1323
1324
    inventory = property(_get_inventory,
1325
                         doc="Inventory of this Tree")
1326
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1327
    def get_parent_ids(self):
1328
        """The parents of a tree in the dirstate are not cached."""
1329
        return self._repository.get_revision(self._revision_id).parent_ids
1330
2255.2.30 by Robert Collins
Some workingtree_implementations/test_workingtree.py test work - add DirStateRevisionTree.has_filename, locks around appropriate calls in tests.
1331
    def has_filename(self, filename):
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
1332
        return bool(self.path2id(filename))
2255.2.30 by Robert Collins
Some workingtree_implementations/test_workingtree.py test work - add DirStateRevisionTree.has_filename, locks around appropriate calls in tests.
1333
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1334
    def is_executable(self, file_id, path=None):
1335
        ie = self.inventory[file_id]
1336
        if ie.kind != "file":
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1337
            return None
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1338
        return ie.executable
1339
2255.2.159 by Martin Pool
reference-trees in dirstate pass all tests.
1340
    @needs_read_lock
1341
    def kind(self, file_id):
1342
        return self.inventory[file_id].kind
1343
2255.2.71 by John Arbash Meinel
Add a test for list_files, and implement it for DirStateRevisionTree
1344
    def list_files(self, include_root=False):
1345
        # We use a standard implementation, because DirStateRevisionTree is
1346
        # dealing with one of the parents of the current state
1347
        inv = self._get_inventory()
1348
        entries = inv.iter_entries()
1349
        if self.inventory.root is not None and not include_root:
1350
            entries.next()
1351
        for path, entry in entries:
1352
            yield path, 'V', entry.kind, entry.file_id, entry
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1353
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1354
    def lock_read(self):
1355
        """Lock the tree for a set of operations."""
2255.2.79 by Robert Collins
Take out repository locks from Dirstate revision trees, to improve file text access performance.
1356
        if not self._locked:
1357
            self._repository.lock_read()
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
1358
            if self._dirstate._lock_token is None:
1359
                self._dirstate.lock_read()
1360
                self._dirstate_locked = True
2255.2.38 by Robert Collins
Fix WorkingTree4.pull to work.
1361
        self._locked += 1
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1362
2255.2.98 by Robert Collins
Perform path2id lookups in dirstate revision trees from the dirstate index without requiring an inventory.
1363
    @needs_read_lock
2255.2.65 by John Arbash Meinel
override path2id because it should be optimized anyway
1364
    def path2id(self, path):
1365
        """Return the id for path in this tree."""
2255.2.98 by Robert Collins
Perform path2id lookups in dirstate revision trees from the dirstate index without requiring an inventory.
1366
        # lookup by path: faster than splitting and walking the ivnentory.
1367
        entry = self._get_entry(path=path)
1368
        if entry == (None, None):
1369
            return None
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1370
        return entry[0][2]
2255.2.65 by John Arbash Meinel
override path2id because it should be optimized anyway
1371
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1372
    def unlock(self):
1373
        """Unlock, freeing any cache memory used during the lock."""
1374
        # outside of a lock, the inventory is suspect: release it.
2255.2.38 by Robert Collins
Fix WorkingTree4.pull to work.
1375
        self._locked -=1
1376
        if not self._locked:
1377
            self._inventory = None
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
1378
            self._locked = 0
1379
            if self._dirstate_locked:
1380
                self._dirstate.unlock()
1381
                self._dirstate_locked = False
2255.2.79 by Robert Collins
Take out repository locks from Dirstate revision trees, to improve file text access performance.
1382
            self._repository.unlock()
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1383
1384
    def walkdirs(self, prefix=""):
1385
        # TODO: jam 20070215 This is the cheap way by cheating and using the
1386
        #       RevisionTree implementation.
1387
        #       This should be cleaned up to use the much faster Dirstate code
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1388
        #       This is a little tricky, though, because the dirstate is
1389
        #       indexed by current path, not by parent path.
1390
        #       So for now, we just build up the parent inventory, and extract
1391
        #       it the same way RevisionTree does.
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1392
        _directory = 'directory'
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1393
        inv = self._get_inventory()
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1394
        top_id = inv.path2id(prefix)
1395
        if top_id is None:
1396
            pending = []
1397
        else:
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1398
            pending = [(prefix, top_id)]
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1399
        while pending:
1400
            dirblock = []
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1401
            relpath, file_id = pending.pop()
1402
            # 0 - relpath, 1- file-id
1403
            if relpath:
1404
                relroot = relpath + '/'
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1405
            else:
1406
                relroot = ""
1407
            # FIXME: stash the node in pending
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1408
            entry = inv[file_id]
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1409
            for name, child in entry.sorted_children():
1410
                toppath = relroot + name
1411
                dirblock.append((toppath, name, child.kind, None,
1412
                    child.file_id, child.kind
1413
                    ))
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1414
            yield (relpath, entry.file_id), dirblock
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1415
            # push the user specified dirs from dirblock
1416
            for dir in reversed(dirblock):
1417
                if dir[2] == _directory:
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1418
                    pending.append((dir[0], dir[4]))
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
1419
1420
1421
class InterDirStateTree(InterTree):
1422
    """Fast path optimiser for changes_from with dirstate trees."""
1423
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1424
    def __init__(self, source, target):
1425
        super(InterDirStateTree, self).__init__(source, target)
1426
        if not InterDirStateTree.is_compatible(source, target):
1427
            raise Exception, "invalid source %r and target %r" % (source, target)
1428
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
1429
    @staticmethod
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1430
    def make_source_parent_tree(source, target):
1431
        """Change the source tree into a parent of the target."""
1432
        revid = source.commit('record tree')
1433
        target.branch.repository.fetch(source.branch.repository, revid)
1434
        target.set_parent_ids([revid])
1435
        return target.basis_tree(), target
2255.7.25 by John Arbash Meinel
Shave off 200+ ms of 'time bzr status' in lp tree
1436
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
1437
    _matching_from_tree_format = WorkingTreeFormat4()
1438
    _matching_to_tree_format = WorkingTreeFormat4()
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1439
    _test_mutable_trees_to_test_trees = make_source_parent_tree
1440
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1441
    def _iter_changes(self, include_unchanged=False,
1442
                      specific_files=None, pb=None, extra_trees=[],
1443
                      require_versioned=True):
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1444
        """Return the changes from source to target.
1445
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1446
        :return: An iterator that yields tuples. See InterTree._iter_changes
1447
            for details.
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1448
        :param specific_files: An optional list of file paths to restrict the
1449
            comparison to. When mapping filenames to ids, all matches in all
1450
            trees (including optional extra_trees) are used, and all children of
1451
            matched directories are included.
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1452
        :param include_unchanged: An optional boolean requesting the inclusion of
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1453
            unchanged entries in the result.
1454
        :param extra_trees: An optional list of additional trees to use when
1455
            mapping the contents of specific_files (paths) to file_ids.
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1456
        :param require_versioned: If True, all files in specific_files must be
1457
            versioned in one of source, target, extra_trees or
1458
            PathsNotVersionedError is raised.
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1459
        """
2255.7.31 by John Arbash Meinel
Minor cleanup.
1460
        utf8_decode = cache_utf8._utf8_decode
1461
        _minikind_to_kind = dirstate.DirState._minikind_to_kind
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1462
        # NB: show_status depends on being able to pass in non-versioned files
1463
        # and report them as unknown
2255.2.155 by Martin Pool
Better assertion message from InterDirStateTree._iter_changes
1464
        # TODO: handle extra trees in the dirstate.
1465
        # TODO: handle comparisons as an empty tree as a different special
1466
        # case? mbp 20070226
1467
        if extra_trees or (self.source._revision_id == NULL_REVISION):
1468
            # we can't fast-path these cases (yet)
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1469
            for f in super(InterDirStateTree, self)._iter_changes(
1470
                include_unchanged, specific_files, pb, extra_trees,
1471
                require_versioned):
1472
                yield f
1473
            return
2255.7.1 by John Arbash Meinel
_iter_changes should return Unicode paths.
1474
        parent_ids = self.target.get_parent_ids()
2255.2.160 by Martin Pool
(merge) updates from dirstate branch
1475
        assert (self.source._revision_id in parent_ids), \
2255.2.154 by Martin Pool
Better assertion message from InterDirStateTree._iter_changes
1476
                "revision {%s} is not stored in {%s}, but %s " \
1477
                "can only be used for trees stored in the dirstate" \
1478
                % (self.source._revision_id, self.target, self._iter_changes)
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1479
        target_index = 0
2255.7.1 by John Arbash Meinel
_iter_changes should return Unicode paths.
1480
        if self.source._revision_id == NULL_REVISION:
1481
            source_index = None
1482
            indices = (target_index,)
1483
        else:
1484
            assert (self.source._revision_id in parent_ids), \
1485
                "Failure: source._revision_id: %s not in target.parent_ids(%s)" % (
1486
                self.source._revision_id, parent_ids)
1487
            source_index = 1 + parent_ids.index(self.source._revision_id)
1488
            indices = (source_index,target_index)
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1489
        # -- make all specific_files utf8 --
1490
        if specific_files:
1491
            specific_files_utf8 = set()
1492
            for path in specific_files:
1493
                specific_files_utf8.add(path.encode('utf8'))
1494
            specific_files = specific_files_utf8
1495
        else:
1496
            specific_files = set([''])
1497
        # -- specific_files is now a utf8 path set --
1498
        # -- get the state object and prepare it.
1499
        state = self.target.current_dirstate()
1500
        state._read_dirblocks_if_needed()
1501
        def _entries_for_path(path):
1502
            """Return a list with all the entries that match path for all ids.
1503
            """
1504
            dirname, basename = os.path.split(path)
1505
            key = (dirname, basename, '')
1506
            block_index, present = state._find_block_index_from_key(key)
1507
            if not present:
1508
                # the block which should contain path is absent.
1509
                return []
1510
            result = []
1511
            block = state._dirblocks[block_index][1]
1512
            entry_index, _ = state._find_entry_index(key, block)
1513
            # we may need to look at multiple entries at this path: walk while the specific_files match.
1514
            while (entry_index < len(block) and
1515
                block[entry_index][0][0:2] == key[0:2]):
1516
                result.append(block[entry_index])
1517
                entry_index += 1
1518
            return result
1519
        if require_versioned:
1520
            # -- check all supplied paths are versioned in a search tree. --
1521
            all_versioned = True
1522
            for path in specific_files:
1523
                path_entries = _entries_for_path(path)
1524
                if not path_entries:
1525
                    # this specified path is not present at all: error
1526
                    all_versioned = False
1527
                    break
1528
                found_versioned = False
1529
                # for each id at this path
1530
                for entry in path_entries:
1531
                    # for each tree.
2255.7.1 by John Arbash Meinel
_iter_changes should return Unicode paths.
1532
                    for index in indices:
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1533
                        if entry[1][index][0] != 'a': # absent
1534
                            found_versioned = True
1535
                            # all good: found a versioned cell
1536
                            break
1537
                if not found_versioned:
1538
                    # none of the indexes was not 'absent' at all ids for this
1539
                    # path.
1540
                    all_versioned = False
1541
                    break
1542
            if not all_versioned:
1543
                raise errors.PathsNotVersionedError(paths)
1544
        # -- remove redundancy in supplied specific_files to prevent over-scanning --
1545
        search_specific_files = set()
1546
        for path in specific_files:
1547
            other_specific_files = specific_files.difference(set([path]))
1548
            if not osutils.is_inside_any(other_specific_files, path):
1549
                # this is a top level path, we must check it.
1550
                search_specific_files.add(path)
1551
        # sketch: 
1552
        # compare source_index and target_index at or under each element of search_specific_files.
1553
        # follow the following comparison table. Note that we only want to do diff operations when
1554
        # the target is fdl because thats when the walkdirs logic will have exposed the pathinfo 
1555
        # for the target.
1556
        # cases:
1557
        # 
1558
        # Source | Target | disk | action
1559
        #   r    | fdl    |      | add source to search, add id path move and perform
1560
        #        |        |      | diff check on source-target
1561
        #   r    | fdl    |  a   | dangling file that was present in the basis. 
1562
        #        |        |      | ???
1563
        #   r    |  a     |      | add source to search
1564
        #   r    |  a     |  a   | 
1565
        #   r    |  r     |      | this path is present in a non-examined tree, skip.
1566
        #   r    |  r     |  a   | this path is present in a non-examined tree, skip.
1567
        #   a    | fdl    |      | add new id
1568
        #   a    | fdl    |  a   | dangling locally added file, skip
1569
        #   a    |  a     |      | not present in either tree, skip
1570
        #   a    |  a     |  a   | not present in any tree, skip
1571
        #   a    |  r     |      | not present in either tree at this path, skip as it
1572
        #        |        |      | may not be selected by the users list of paths.
1573
        #   a    |  r     |  a   | not present in either tree at this path, skip as it
1574
        #        |        |      | may not be selected by the users list of paths.
1575
        #  fdl   | fdl    |      | content in both: diff them
1576
        #  fdl   | fdl    |  a   | deleted locally, but not unversioned - show as deleted ?
1577
        #  fdl   |  a     |      | unversioned: output deleted id for now
1578
        #  fdl   |  a     |  a   | unversioned and deleted: output deleted id
1579
        #  fdl   |  r     |      | relocated in this tree, so add target to search.
1580
        #        |        |      | Dont diff, we will see an r,fd; pair when we reach
1581
        #        |        |      | this id at the other path.
1582
        #  fdl   |  r     |  a   | relocated in this tree, so add target to search.
1583
        #        |        |      | Dont diff, we will see an r,fd; pair when we reach
1584
        #        |        |      | this id at the other path.
1585
1586
        # for all search_indexs in each path at or under each element of
1587
        # search_specific_files, if the detail is relocated: add the id, and add the
1588
        # relocated path as one to search if its not searched already. If the
1589
        # detail is not relocated, add the id.
1590
        searched_specific_files = set()
2255.7.1 by John Arbash Meinel
_iter_changes should return Unicode paths.
1591
        NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
2255.7.29 by John Arbash Meinel
approx 300ms of 'time bzr status' in lp tree by caching last parent info
1592
        # Using a list so that we can access the values and change them in
1593
        # nested scope. Each one is [path, file_id, entry]
1594
        last_source_parent = [None, None, None]
1595
        last_target_parent = [None, None, None]
1596
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1597
        def _process_entry(entry, path_info):
1598
            """Compare an entry and real disk to generate delta information.
1599
1600
            :param path_info: top_relpath, basename, kind, lstat, abspath for
1601
                the path of entry. If None, then the path is considered absent.
1602
                (Perhaps we should pass in a concrete entry for this ?)
1603
            """
1604
            # TODO: when a parent has been renamed, dont emit path renames for children,
2255.7.1 by John Arbash Meinel
_iter_changes should return Unicode paths.
1605
            if source_index is None:
1606
                source_details = NULL_PARENT_DETAILS
1607
            else:
1608
                source_details = entry[1][source_index]
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1609
            target_details = entry[1][target_index]
2255.7.31 by John Arbash Meinel
Minor cleanup.
1610
            source_minikind = source_details[0]
1611
            target_minikind = target_details[0]
1612
            if source_minikind in 'fdlr' and target_minikind in 'fdl':
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1613
                # claimed content in both: diff
1614
                #   r    | fdl    |      | add source to search, add id path move and perform
1615
                #        |        |      | diff check on source-target
2255.7.31 by John Arbash Meinel
Minor cleanup.
1616
                #   r    | fdl    |  a   | dangling file that was present in the basis.
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1617
                #        |        |      | ???
2255.7.31 by John Arbash Meinel
Minor cleanup.
1618
                if source_minikind in 'r':
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1619
                    # add the source to the search path to find any children it
1620
                    # has.  TODO ? : only add if it is a container ?
2255.7.31 by John Arbash Meinel
Minor cleanup.
1621
                    if not osutils.is_inside_any(searched_specific_files,
1622
                                                 source_details[1]):
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1623
                        search_specific_files.add(source_details[1])
1624
                    # generate the old path; this is needed for stating later
1625
                    # as well.
1626
                    old_path = source_details[1]
1627
                    old_dirname, old_basename = os.path.split(old_path)
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1628
                    path = os.path.join(entry[0][0], entry[0][1])
2255.7.31 by John Arbash Meinel
Minor cleanup.
1629
                    old_entry = state._get_entry(source_index,
1630
                                                 path_utf8=old_path)
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1631
                    # update the source details variable to be the real
1632
                    # location.
1633
                    source_details = old_entry[1][source_index]
2255.7.31 by John Arbash Meinel
Minor cleanup.
1634
                    source_minikind = source_details[0]
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1635
                else:
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1636
                    old_dirname = entry[0][0]
1637
                    old_basename = entry[0][1]
1638
                    old_path = path = os.path.join(old_dirname, old_basename)
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1639
                if path_info is None:
1640
                    # the file is missing on disk, show as removed.
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1641
                    old_path = os.path.join(entry[0][0], entry[0][1])
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
1642
                    content_change = True
1643
                    target_kind = None
1644
                    target_exec = False
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1645
                else:
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
1646
                    # source and target are both versioned and disk file is present.
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
1647
                    target_kind = path_info[2]
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1648
                    if target_kind == 'directory':
2255.7.31 by John Arbash Meinel
Minor cleanup.
1649
                        if source_minikind != 'd':
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
1650
                            content_change = True
1651
                        else:
1652
                            # directories have no fingerprint
1653
                            content_change = False
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
1654
                        target_exec = False
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1655
                    elif target_kind == 'file':
2255.7.31 by John Arbash Meinel
Minor cleanup.
1656
                        if source_minikind != 'f':
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
1657
                            content_change = True
1658
                        else:
1659
                            # has it changed? fast path: size, slow path: sha1.
1660
                            if source_details[2] != path_info[3].st_size:
1661
                                content_change = True
1662
                            else:
1663
                                # maybe the same. Get the hash
2255.7.31 by John Arbash Meinel
Minor cleanup.
1664
                                new_hash = self.target._hashcache.get_sha1(
1665
                                                            path, path_info[3])
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
1666
                                content_change = (new_hash != source_details[1])
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
1667
                        target_exec = bool(
1668
                            stat.S_ISREG(path_info[3].st_mode)
1669
                            and stat.S_IEXEC & path_info[3].st_mode)
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1670
                    elif target_kind == 'symlink':
2255.7.31 by John Arbash Meinel
Minor cleanup.
1671
                        if source_minikind != 'l':
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
1672
                            content_change = True
1673
                        else:
2255.7.31 by John Arbash Meinel
Minor cleanup.
1674
                            # TODO: check symlink supported for windows users
1675
                            # and grab from target state here.
1676
                            link_target = os.readlink(path_info[4])
1677
                            content_change = (link_target != source_details[1])
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
1678
                        target_exec = False
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1679
                    else:
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
1680
                        raise Exception, "unknown kind %s" % path_info[2]
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
1681
                # parent id is the entry for the path in the target tree
2255.7.29 by John Arbash Meinel
approx 300ms of 'time bzr status' in lp tree by caching last parent info
1682
                if old_dirname == last_source_parent[0]:
1683
                    source_parent_id = last_source_parent[1]
1684
                else:
1685
                    source_parent_entry = state._get_entry(source_index,
1686
                                                           path_utf8=old_dirname)
1687
                    source_parent_id = source_parent_entry[0][2]
1688
                    if source_parent_id == entry[0][2]:
1689
                        # This is the root, so the parent is None
1690
                        source_parent_id = None
2255.7.30 by John Arbash Meinel
Don't cache the parent entry for root, since it is different than all other entries.
1691
                    else:
1692
                        last_source_parent[0] = old_dirname
1693
                        last_source_parent[1] = source_parent_id
1694
                        last_source_parent[2] = source_parent_entry
2255.7.29 by John Arbash Meinel
approx 300ms of 'time bzr status' in lp tree by caching last parent info
1695
1696
                new_dirname = entry[0][0]
1697
                if new_dirname == last_target_parent[0]:
1698
                    target_parent_id = last_target_parent[1]
1699
                else:
1700
                    # TODO: We don't always need to do the lookup, because the
1701
                    #       parent entry will be the same as the source entry.
2255.7.25 by John Arbash Meinel
Shave off 200+ ms of 'time bzr status' in lp tree
1702
                    target_parent_entry = state._get_entry(target_index,
2255.7.29 by John Arbash Meinel
approx 300ms of 'time bzr status' in lp tree by caching last parent info
1703
                                                           path_utf8=new_dirname)
2255.7.25 by John Arbash Meinel
Shave off 200+ ms of 'time bzr status' in lp tree
1704
                    target_parent_id = target_parent_entry[0][2]
1705
                    if target_parent_id == entry[0][2]:
1706
                        # This is the root, so the parent is None
1707
                        target_parent_id = None
2255.7.30 by John Arbash Meinel
Don't cache the parent entry for root, since it is different than all other entries.
1708
                    else:
1709
                        last_target_parent[0] = new_dirname
1710
                        last_target_parent[1] = target_parent_id
1711
                        last_target_parent[2] = target_parent_entry
2255.7.29 by John Arbash Meinel
approx 300ms of 'time bzr status' in lp tree by caching last parent info
1712
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
1713
                source_exec = source_details[3]
2255.7.31 by John Arbash Meinel
Minor cleanup.
1714
                path_unicode = utf8_decode(path)[0]
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
1715
                return ((entry[0][2], path_unicode, content_change,
1716
                        (True, True),
1717
                        (source_parent_id, target_parent_id),
1718
                        (old_basename, entry[0][1]),
2255.7.31 by John Arbash Meinel
Minor cleanup.
1719
                        (_minikind_to_kind[source_minikind], target_kind),
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
1720
                        (source_exec, target_exec)),)
2255.7.31 by John Arbash Meinel
Minor cleanup.
1721
            elif source_minikind in 'a' and target_minikind in 'fdl':
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1722
                # looks like a new file
1723
                if path_info is not None:
1724
                    path = os.path.join(*entry[0][0:2])
1725
                    # parent id is the entry for the path in the target tree
1726
                    # TODO: these are the same for an entire directory: cache em.
1727
                    parent_id = state._get_entry(target_index, path_utf8=entry[0][0])[0][2]
1728
                    if parent_id == entry[0][2]:
1729
                        parent_id = None
1730
                    # basename
1731
                    new_executable = bool(
1732
                        stat.S_ISREG(path_info[3].st_mode)
1733
                        and stat.S_IEXEC & path_info[3].st_mode)
2255.7.31 by John Arbash Meinel
Minor cleanup.
1734
                    path_unicode = utf8_decode(path)[0]
2255.7.1 by John Arbash Meinel
_iter_changes should return Unicode paths.
1735
                    return ((entry[0][2], path_unicode, True,
1736
                            (False, True),
1737
                            (None, parent_id),
1738
                            (None, entry[0][1]),
1739
                            (None, path_info[2]),
1740
                            (None, new_executable)),)
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1741
                else:
1742
                    # but its not on disk: we deliberately treat this as just
1743
                    # never-present. (Why ?! - RBC 20070224)
1744
                    pass
2255.7.31 by John Arbash Meinel
Minor cleanup.
1745
            elif source_minikind in 'fdl' and target_minikind in 'a':
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1746
                # unversioned, possibly, or possibly not deleted: we dont care.
1747
                # if its still on disk, *and* theres no other entry at this
1748
                # path [we dont know this in this routine at the moment -
1749
                # perhaps we should change this - then it would be an unknown.
1750
                old_path = os.path.join(*entry[0][0:2])
1751
                # parent id is the entry for the path in the target tree
1752
                parent_id = state._get_entry(source_index, path_utf8=entry[0][0])[0][2]
1753
                if parent_id == entry[0][2]:
1754
                    parent_id = None
2255.7.31 by John Arbash Meinel
Minor cleanup.
1755
                old_path_unicode = utf8_decode(old_path)[0]
2255.7.1 by John Arbash Meinel
_iter_changes should return Unicode paths.
1756
                return ((entry[0][2], old_path_unicode, True,
1757
                        (True, False),
1758
                        (parent_id, None),
1759
                        (entry[0][1], None),
2255.7.31 by John Arbash Meinel
Minor cleanup.
1760
                        (_minikind_to_kind[source_minikind], None),
2255.7.1 by John Arbash Meinel
_iter_changes should return Unicode paths.
1761
                        (source_details[3], None)),)
2255.7.31 by John Arbash Meinel
Minor cleanup.
1762
            elif source_minikind in 'fdl' and target_minikind in 'r':
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1763
                # a rename; could be a true rename, or a rename inherited from
1764
                # a renamed parent. TODO: handle this efficiently. Its not
1765
                # common case to rename dirs though, so a correct but slow
1766
                # implementation will do.
1767
                if not osutils.is_inside_any(searched_specific_files, target_details[1]):
1768
                    search_specific_files.add(target_details[1])
1769
            else:
1770
                import pdb;pdb.set_trace()
1771
            return ()
1772
        while search_specific_files:
1773
            # TODO: the pending list should be lexically sorted?
1774
            current_root = search_specific_files.pop()
1775
            searched_specific_files.add(current_root)
1776
            # process the entries for this containing directory: the rest will be
1777
            # found by their parents recursively.
1778
            root_entries = _entries_for_path(current_root)
1779
            root_abspath = self.target.abspath(current_root)
1780
            try:
1781
                root_stat = os.lstat(root_abspath)
1782
            except OSError, e:
1783
                if e.errno == errno.ENOENT:
2255.2.151 by Robert Collins
Handle specific_files natively for WorkingTreeFormat4._iter_changes.
1784
                    # the path does not exist: let _process_entry know that.
1785
                    root_dir_info = None
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1786
                else:
1787
                    # some other random error: hand it up.
1788
                    raise
2255.2.151 by Robert Collins
Handle specific_files natively for WorkingTreeFormat4._iter_changes.
1789
            else:
1790
                root_dir_info = ('', current_root,
1791
                    osutils.file_kind_from_stat_mode(root_stat.st_mode), root_stat,
1792
                    root_abspath)
1793
            if not root_entries and not root_dir_info:
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1794
                # this specified path is not present at all, skip it.
1795
                continue
1796
            for entry in root_entries:
1797
                for result in _process_entry(entry, root_dir_info):
1798
                    # this check should probably be outside the loop: one
1799
                    # 'iterate two trees' api, and then _iter_changes filters
1800
                    # unchanged pairs. - RBC 20070226
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1801
                    if (include_unchanged
1802
                        or result[2]                    # content change
1803
                        or result[3][0] != result[3][1] # versioned status
1804
                        or result[4][0] != result[4][1] # parent id
1805
                        or result[5][0] != result[5][1] # name
1806
                        or result[6][0] != result[6][1] # kind
1807
                        or result[7][0] != result[7][1] # executable
1808
                        ):
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1809
                        yield result
2255.7.28 by John Arbash Meinel
shave about 10% of the time by switching to _walkdirs_utf8
1810
            dir_iterator = osutils._walkdirs_utf8(root_abspath, prefix=current_root)
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1811
            initial_key = (current_root, '', '')
1812
            block_index, _ = state._find_block_index_from_key(initial_key)
1813
            if block_index == 0:
1814
                # we have processed the total root already, but because the
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1815
                # initial key matched it we should skip it here.
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1816
                block_index +=1
2255.2.151 by Robert Collins
Handle specific_files natively for WorkingTreeFormat4._iter_changes.
1817
            try:
1818
                current_dir_info = dir_iterator.next()
1819
            except OSError, e:
1820
                if e.errno in (errno.ENOENT, errno.ENOTDIR):
1821
                    # there may be directories in the inventory even though
1822
                    # this path is not a file on disk: so mark it as end of
1823
                    # iterator
1824
                    current_dir_info = None
1825
                else:
1826
                    raise
1827
            else:
1828
                if current_dir_info[0][0] == '':
1829
                    # remove .bzr from iteration
1830
                    bzr_index = bisect_left(current_dir_info[1], ('.bzr',))
1831
                    assert current_dir_info[1][bzr_index][0] == '.bzr'
1832
                    del current_dir_info[1][bzr_index]
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1833
            # walk until both the directory listing and the versioned metadata
1834
            # are exhausted. TODO: reevaluate this, perhaps we should stop when
1835
            # the versioned data runs out.
1836
            if (block_index < len(state._dirblocks) and
1837
                osutils.is_inside(current_root, state._dirblocks[block_index][0])):
1838
                current_block = state._dirblocks[block_index]
1839
            else:
1840
                current_block = None
1841
            while (current_dir_info is not None or
2255.7.35 by John Arbash Meinel
Handle the case when a directory has been removed, and isn't the last entry.
1842
                   current_block is not None):
1843
                if (current_dir_info and current_block
1844
                    and current_dir_info[0][0] != current_block[0]):
1845
                    if current_dir_info[0][0] < current_block[0] :
1846
                        # import pdb; pdb.set_trace()
1847
                        # print 'unversioned dir'
1848
                        # filesystem data refers to paths not covered by the dirblock.
2255.7.6 by Robert Collins
Test for iterating changes past empty directories.
1849
                        # this has two possibilities:
1850
                        # A) it is versioned but empty, so there is no block for it
1851
                        # B) it is not versioned.
1852
                        # in either case it was processed by the containing directories walk:
1853
                        # if it is root/foo, when we walked root we emitted it,
1854
                        # or if we ere given root/foo to walk specifically, we
2255.7.35 by John Arbash Meinel
Handle the case when a directory has been removed, and isn't the last entry.
1855
                        # emitted it when checking the walk-root entries
2255.7.6 by Robert Collins
Test for iterating changes past empty directories.
1856
                        # advance the iterator and loop - we dont need to emit it.
1857
                        try:
1858
                            current_dir_info = dir_iterator.next()
1859
                        except StopIteration:
1860
                            current_dir_info = None
2255.7.35 by John Arbash Meinel
Handle the case when a directory has been removed, and isn't the last entry.
1861
                    else:
1862
                        # We have a dirblock entry for this location, but there
1863
                        # is no filesystem path for this. This is most likely
1864
                        # because a directory was removed from the disk.
1865
                        # We don't have to report the missing directory,
1866
                        # because that should have already been handled, but we
1867
                        # need to handle all of the files that are contained
1868
                        # within.
1869
                        for current_entry in current_block[1]:
1870
                            # entry referring to file not present on disk.
1871
                            # advance the entry only, after processing.
1872
                            for result in _process_entry(current_entry, None):
1873
                                # this check should probably be outside the loop: one
1874
                                # 'iterate two trees' api, and then _iter_changes filters
1875
                                # unchanged pairs. - RBC 20070226
1876
                                if (include_unchanged
1877
                                    or result[2]                    # content change
1878
                                    or result[3][0] != result[3][1] # versioned status
1879
                                    or result[4][0] != result[4][1] # parent id
1880
                                    or result[5][0] != result[5][1] # name
1881
                                    or result[6][0] != result[6][1] # kind
1882
                                    or result[7][0] != result[7][1] # executable
1883
                                    ):
1884
                                    yield result
1885
                        block_index +=1
1886
                        if (block_index < len(state._dirblocks) and
1887
                            osutils.is_inside(current_root,
1888
                                              state._dirblocks[block_index][0])):
1889
                            current_block = state._dirblocks[block_index]
1890
                        else:
1891
                            current_block = None
2255.7.7 by Robert Collins
continue iteration at the right point for InterDirStateTree._iter_changes.
1892
                    continue
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1893
                entry_index = 0
1894
                if current_block and entry_index < len(current_block[1]):
1895
                    current_entry = current_block[1][entry_index]
1896
                else:
1897
                    current_entry = None
1898
                advance_entry = True
1899
                path_index = 0
1900
                if current_dir_info and path_index < len(current_dir_info[1]):
1901
                    current_path_info = current_dir_info[1][path_index]
1902
                else:
1903
                    current_path_info = None
1904
                advance_path = True
1905
                while (current_entry is not None or
1906
                    current_path_info is not None):
1907
                    if current_entry is None:
1908
                        # no more entries: yield current_pathinfo as an
1909
                        # unversioned file: its not the same as a path in any
1910
                        # tree in the dirstate.
1911
                        new_executable = bool(
1912
                            stat.S_ISREG(current_path_info[3].st_mode)
1913
                            and stat.S_IEXEC & current_path_info[3].st_mode)
2255.7.34 by John Arbash Meinel
Clean up test_bad_files, and fix a bug in _iter_changes when
1914
                        yield (None, current_path_info[0], True,
1915
                               (False, False),
1916
                               (None, None),
1917
                               (None, current_path_info[1]),
1918
                               (None, current_path_info[2]),
1919
                               (None, new_executable))
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1920
                    elif current_path_info is None:
1921
                        # no path is fine: the per entry code will handle it.
1922
                        for result in _process_entry(current_entry, current_path_info):
1923
                            # this check should probably be outside the loop: one
1924
                            # 'iterate two trees' api, and then _iter_changes filters
1925
                            # unchanged pairs. - RBC 20070226
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1926
                            if (include_unchanged
1927
                                or result[2]                    # content change
1928
                                or result[3][0] != result[3][1] # versioned status
1929
                                or result[4][0] != result[4][1] # parent id
1930
                                or result[5][0] != result[5][1] # name
1931
                                or result[6][0] != result[6][1] # kind
1932
                                or result[7][0] != result[7][1] # executable
1933
                                ):
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1934
                                yield result
1935
                    elif current_entry[0][1] != current_path_info[1]:
1936
                        if current_path_info[1] < current_entry[0][1]:
2255.7.34 by John Arbash Meinel
Clean up test_bad_files, and fix a bug in _iter_changes when
1937
                            # extra file on disk: pass for now, but only
1938
                            # increment the path, not the entry
1939
                            # import pdb; pdb.set_trace()
1940
                            # print 'unversioned file'
1941
                            advance_entry = False
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1942
                        else:
1943
                            # entry referring to file not present on disk.
1944
                            # advance the entry only, after processing.
1945
                            for result in _process_entry(current_entry, None):
1946
                                # this check should probably be outside the loop: one
1947
                                # 'iterate two trees' api, and then _iter_changes filters
1948
                                # unchanged pairs. - RBC 20070226
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1949
                                if (include_unchanged
1950
                                    or result[2]                    # content change
1951
                                    or result[3][0] != result[3][1] # versioned status
1952
                                    or result[4][0] != result[4][1] # parent id
1953
                                    or result[5][0] != result[5][1] # name
1954
                                    or result[6][0] != result[6][1] # kind
1955
                                    or result[7][0] != result[7][1] # executable
1956
                                    ):
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1957
                                    yield result
1958
                            advance_path = False
1959
                    else:
1960
                        for result in _process_entry(current_entry, current_path_info):
1961
                            # this check should probably be outside the loop: one
1962
                            # 'iterate two trees' api, and then _iter_changes filters
1963
                            # unchanged pairs. - RBC 20070226
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1964
                            if (include_unchanged
1965
                                or result[2]                    # content change
1966
                                or result[3][0] != result[3][1] # versioned status
1967
                                or result[4][0] != result[4][1] # parent id
1968
                                or result[5][0] != result[5][1] # name
1969
                                or result[6][0] != result[6][1] # kind
1970
                                or result[7][0] != result[7][1] # executable
1971
                                ):
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
1972
                                yield result
1973
                    if advance_entry and current_entry is not None:
1974
                        entry_index += 1
1975
                        if entry_index < len(current_block[1]):
1976
                            current_entry = current_block[1][entry_index]
1977
                        else:
1978
                            current_entry = None
1979
                    else:
1980
                        advance_entry = True # reset the advance flaga
1981
                    if advance_path and current_path_info is not None:
1982
                        path_index += 1
1983
                        if path_index < len(current_dir_info[1]):
1984
                            current_path_info = current_dir_info[1][path_index]
1985
                        else:
1986
                            current_path_info = None
1987
                    else:
1988
                        advance_path = True # reset the advance flagg.
1989
                if current_block is not None:
1990
                    block_index += 1
1991
                    if (block_index < len(state._dirblocks) and
1992
                        osutils.is_inside(current_root, state._dirblocks[block_index][0])):
1993
                        current_block = state._dirblocks[block_index]
1994
                    else:
1995
                        current_block = None
1996
                if current_dir_info is not None:
1997
                    try:
1998
                        current_dir_info = dir_iterator.next()
1999
                    except StopIteration:
2000
                        current_dir_info = None
2001
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
2002
2003
    @staticmethod
2004
    def is_compatible(source, target):
2005
        # the target must be a dirstate working tree
2006
        if not isinstance(target, WorkingTree4):
2007
            return False
2008
        # the source must be a revtreee or dirstate rev tree.
2009
        if not isinstance(source,
2010
            (revisiontree.RevisionTree, DirStateRevisionTree)):
2011
            return False
2012
        # the source revid must be in the target dirstate
2013
        if not (source._revision_id == NULL_REVISION or
2014
            source._revision_id in target.get_parent_ids()):
2015
            # TODO: what about ghosts? it may well need to 
2016
            # check for them explicitly.
2017
            return False
2018
        return True
2019
2020
InterTree.register_optimiser(InterDirStateTree)