/brz/remove-bazaar

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