/brz/remove-bazaar

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