/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""WorkingTree4 format and implementation.
18
19
WorkingTree4 provides the dirstate based working tree logic.
20
21
To get a WorkingTree, call bzrdir.open_workingtree() or
22
WorkingTree.open(dir).
23
"""
24
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
25
from cStringIO import StringIO
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
26
import os
2255.2.138 by John Arbash Meinel
implement several new WorkingTree.move() tests
27
import sys
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
28
29
from bzrlib.lazy_import import lazy_import
30
lazy_import(globals(), """
31
from bisect import bisect_left
32
import collections
33
from copy import deepcopy
34
import errno
35
import itertools
36
import operator
37
import stat
38
from time import time
39
import warnings
40
41
import bzrlib
42
from bzrlib import (
43
    bzrdir,
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
44
    cache_utf8,
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
45
    conflicts as _mod_conflicts,
46
    dirstate,
47
    errors,
48
    generate_ids,
49
    globbing,
50
    hashcache,
51
    ignores,
52
    merge,
53
    osutils,
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
54
    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.
55
    textui,
56
    transform,
57
    urlutils,
58
    xml5,
59
    xml6,
60
    )
61
import bzrlib.branch
62
from bzrlib.transport import get_transport
63
import bzrlib.ui
64
""")
65
66
from bzrlib import symbol_versioning
67
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.
68
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.
69
from bzrlib.lockable_files import LockableFiles, TransportLock
70
from bzrlib.lockdir import LockDir
71
import bzrlib.mutabletree
72
from bzrlib.mutabletree import needs_tree_write_lock
73
from bzrlib.osutils import (
74
    compact_date,
75
    file_kind,
76
    isdir,
77
    normpath,
78
    pathjoin,
79
    rand_chars,
80
    realpath,
81
    safe_unicode,
82
    splitpath,
83
    supports_executable,
84
    )
85
from bzrlib.trace import mutter, note
86
from bzrlib.transport.local import LocalTransport
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
87
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.
88
from bzrlib.progress import DummyProgress, ProgressPhase
89
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
90
from bzrlib.rio import RioReader, rio_file, Stanza
91
from bzrlib.symbol_versioning import (deprecated_passed,
92
        deprecated_method,
93
        deprecated_function,
94
        DEPRECATED_PARAMETER,
95
        zero_eight,
96
        zero_eleven,
97
        zero_thirteen,
98
        )
99
from bzrlib.tree import Tree
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
100
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.
101
102
103
class WorkingTree4(WorkingTree3):
104
    """This is the Format 4 working tree.
105
106
    This differs from WorkingTree3 by:
107
     - having a consolidated internal dirstate.
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
108
     - not having a regular inventory attribute.
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
109
110
    This is new in bzr TODO FIXME SETMEBEFORE MERGE.
111
    """
112
113
    def __init__(self, basedir,
114
                 branch,
115
                 _control_files=None,
116
                 _format=None,
117
                 _bzrdir=None):
118
        """Construct a WorkingTree for basedir.
119
120
        If the branch is not supplied, it is opened automatically.
121
        If the branch is supplied, it must be the branch for this basedir.
122
        (branch.base is not cross checked, because for remote branches that
123
        would be meaningless).
124
        """
125
        self._format = _format
126
        self.bzrdir = _bzrdir
127
        from bzrlib.hashcache import HashCache
128
        from bzrlib.trace import note, mutter
129
        assert isinstance(basedir, basestring), \
130
            "base directory %r is not a string" % basedir
131
        basedir = safe_unicode(basedir)
132
        mutter("opening working tree %r", basedir)
133
        self._branch = branch
134
        assert isinstance(self.branch, bzrlib.branch.Branch), \
135
            "branch %r is not a Branch" % self.branch
136
        self.basedir = realpath(basedir)
137
        # if branch is at our basedir and is a format 6 or less
138
        # assume all other formats have their own control files.
139
        assert isinstance(_control_files, LockableFiles), \
140
            "_control_files must be a LockableFiles, not %r" % _control_files
141
        self._control_files = _control_files
142
        # update the whole cache up front and write to disk if anything changed;
143
        # in the future we might want to do this more selectively
144
        # two possible ways offer themselves : in self._unlock, write the cache
145
        # if needed, or, when the cache sees a change, append it to the hash
146
        # cache file, and have the parser take the most recent entry for a
147
        # given path only.
148
        cache_filename = self.bzrdir.get_workingtree_transport(None).local_abspath('stat-cache')
149
        hc = self._hashcache = HashCache(basedir, cache_filename, self._control_files._file_mode)
150
        hc.read()
151
        # is this scan needed ? it makes things kinda slow.
152
        #hc.scan()
153
154
        if hc.needs_write:
155
            mutter("write hc")
156
            hc.write()
157
158
        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.
159
        #-------------
160
        # during a read or write lock these objects are set, and are
161
        # 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.
162
        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.
163
        self._inventory = None
164
        #-------------
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
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
166
    @needs_tree_write_lock
2255.2.12 by Robert Collins
Partial implementation of WorkingTree4._add.
167
    def _add(self, files, ids, kinds):
168
        """See MutableTree._add."""
169
        state = self.current_dirstate()
170
        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.
171
            f = f.strip('/')
2255.2.12 by Robert Collins
Partial implementation of WorkingTree4._add.
172
            assert '//' not in f
173
            assert '..' not in f
174
            if file_id is None:
2255.2.20 by Robert Collins
Bypass irrelevant basis_inventory tests for dirstate.
175
                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.
176
            # deliberately add the file with no cached stat or sha1
177
            # - on the first access it will be gathered, and we can
178
            # always change this once tests are all passing.
179
            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.
180
        self._dirty = True
2255.2.12 by Robert Collins
Partial implementation of WorkingTree4._add.
181
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.
182
    def current_dirstate(self):
183
        """Return the current dirstate object. 
184
185
        This is not part of the tree interface and only exposed for ease of
186
        testing.
187
188
        :raises errors.NotWriteLocked: when not in a lock. 
189
            XXX: This should probably be errors.NotLocked.
190
        """
191
        if not self._control_files._lock_count:
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
192
            raise errors.ObjectNotLocked(self)
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.
193
        if self._dirstate is not None:
194
            return self._dirstate
195
        local_path = self.bzrdir.get_workingtree_transport(None
196
            ).local_abspath('dirstate')
197
        self._dirstate = dirstate.DirState.on_file(local_path)
198
        return self._dirstate
199
2255.2.81 by Robert Collins
WorkingTree4: Implement filter_unversioned_files to use dirstate bisection.
200
    def filter_unversioned_files(self, paths):
201
        """Filter out paths that are not versioned.
202
203
        :return: set of paths.
204
        """
205
        # TODO: make a generic multi-bisect routine roughly that should list
206
        # the paths, then process one half at a time recursively, and feed the
207
        # results of each bisect in further still
208
        paths = sorted(paths)
209
        result = set()
210
        state = self.current_dirstate()
211
        # TODO we want a paths_to_dirblocks helper I think
212
        for path in paths:
213
            dirname, basename = os.path.split(path.encode('utf8'))
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
214
            _, _, _, path_is_versioned = state._get_block_entry_index(
215
                dirname, basename, 0)
2255.2.81 by Robert Collins
WorkingTree4: Implement filter_unversioned_files to use dirstate bisection.
216
            if path_is_versioned:
217
                result.add(path)
218
        return result
219
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
220
    def flush(self):
221
        """Write all cached data to disk."""
2255.2.39 by Robert Collins
WorkingTree4: flush can only be used during write locks.
222
        if self._control_files._lock_mode != 'w':
223
            raise errors.NotWriteLocked(self)
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
224
        self.current_dirstate().save()
225
        self._inventory = None
226
        self._dirty = False
227
2255.2.34 by Robert Collins
Fix WorkingTree4 parent_ids logic to use the dirstate to answer parent ids list queries.
228
    def _generate_inventory(self):
229
        """Create and set self.inventory from the dirstate object.
230
        
231
        This is relatively expensive: we have to walk the entire dirstate.
232
        Ideally we would not, and can deprecate this function.
233
        """
2255.2.82 by Robert Collins
various notes about find_ids_across_trees
234
        #: uncomment to trap on inventory requests.
235
        # import pdb;pdb.set_trace()
2255.2.75 by Robert Collins
Correct generation of revisiontree inventories to handle out of order parents.
236
        state = self.current_dirstate()
237
        state._read_dirblocks_if_needed()
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
238
        root_key, current_entry = self._get_entry(path='')
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
239
        current_id = root_key[2]
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
240
        assert current_entry[0][0] == 'd' # directory
2255.2.75 by Robert Collins
Correct generation of revisiontree inventories to handle out of order parents.
241
        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
242
        # Turn some things into local variables
243
        minikind_to_kind = dirstate.DirState._minikind_to_kind
244
        factory = entry_factory
245
        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()
246
        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.
247
        # we could do this straight out of the dirstate; it might be fast
248
        # 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()
249
        parent_ies = {'' : inv.root}
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
250
        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.
251
            dirname = block[0]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
252
            try:
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
253
                parent_ie = parent_ies[block[0]]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
254
            except KeyError:
255
                # all the paths in this block are not versioned in this tree
256
                continue
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
257
            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
258
                minikind, link_or_sha1, size, executable, stat = entry[0]
259
                if minikind in ('a', 'r'): # absent, relocated
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
260
                    # a parent tree only entry
261
                    continue
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
262
                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
263
                name_unicode = utf8_decode(name)[0]
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
264
                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
265
                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()
266
                inv_entry = factory[kind](file_id, name_unicode,
267
                                          parent_ie.file_id)
2255.2.77 by Robert Collins
Tune working inventory generation more: walk the blocks, skipping deleted rows.
268
                if kind == 'file':
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
269
                    # not strictly needed: working tree
2255.2.77 by Robert Collins
Tune working inventory generation more: walk the blocks, skipping deleted rows.
270
                    #entry.executable = executable
271
                    #entry.text_size = size
272
                    #entry.text_sha1 = sha1
273
                    pass
274
                elif kind == 'directory':
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
275
                    # 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()
276
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
277
                # These checks cost us around 40ms on a 55k entry tree
278
                assert file_id not in inv_byid
279
                assert name_unicode not in parent_ie.children
280
                inv_byid[file_id] = inv_entry
281
                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.
282
        self._inventory = inv
283
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
284
    def _get_entry(self, file_id=None, path=None):
285
        """Get the dirstate row for file_id or path.
286
287
        If either file_id or path is supplied, it is used as the key to lookup.
288
        If both are supplied, the fastest lookup is used, and an error is
289
        raised if they do not both point at the same row.
290
        
291
        :param file_id: An optional unicode file_id to be looked up.
292
        :param path: An optional unicode path to be looked up.
293
        :return: The dirstate row tuple for path/file_id, or (None, None)
294
        """
295
        if file_id is None and path is None:
296
            raise errors.BzrError('must supply file_id or path')
297
        state = self.current_dirstate()
298
        if path is not None:
299
            path = path.encode('utf8')
300
        return state._get_entry(0, fileid_utf8=file_id, path_utf8=path)
301
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
302
    def get_file_sha1(self, file_id, path=None, stat_value=None):
2255.2.88 by Robert Collins
Significant steps back to operation.
303
        # check file id is valid unconditionally.
2255.2.95 by Robert Collins
Fix WorkingTree4.get_file_sha1 to actually work.
304
        key, details = self._get_entry(file_id=file_id, path=path)
305
        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.
306
        # TODO:
307
        # 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.
308
        if path is None:
2255.2.95 by Robert Collins
Fix WorkingTree4.get_file_sha1 to actually work.
309
            path = os.path.join(*key[0:2]).decode('utf8')
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
310
        return self._hashcache.get_sha1(path, stat_value)
311
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
312
    def _get_inventory(self):
313
        """Get the inventory for the tree. This is only valid within a lock."""
314
        if self._inventory is not None:
315
            return self._inventory
316
        self._generate_inventory()
317
        return self._inventory
318
319
    inventory = property(_get_inventory,
320
                         doc="Inventory of this Tree")
321
322
    @needs_read_lock
2255.2.34 by Robert Collins
Fix WorkingTree4 parent_ids logic to use the dirstate to answer parent ids list queries.
323
    def get_parent_ids(self):
324
        """See Tree.get_parent_ids.
325
        
326
        This implementation requests the ids list from the dirstate file.
327
        """
328
        return self.current_dirstate().get_parent_ids()
329
330
    @needs_read_lock
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
331
    def get_root_id(self):
332
        """Return the id of this trees root"""
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
333
        return self._get_entry(path='')[0][2]
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
334
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
335
    def has_id(self, file_id):
336
        state = self.current_dirstate()
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
337
        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.
338
        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.
339
        if row is None:
340
            return False
341
        return osutils.lexists(pathjoin(
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
342
                    self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
343
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
344
    @needs_read_lock
345
    def id2path(self, fileid):
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
346
        fileid = osutils.safe_file_id(fileid)
2255.2.116 by John Arbash Meinel
hack in a faster id2path, ultimately we want something different.
347
        inv = self._get_inventory()
348
        return inv.id2path(fileid)
349
        # TODO: jam 20070222 At present dirstate is very slow at id => path,
350
        #       while inventory is very fast at it. So for now, just generate
351
        #       the inventory and do the id => path check.
352
        #       In the future, we want to make dirstate better at id=>path
353
        #       checks so that we don't have to create the inventory.
354
        # state = self.current_dirstate()
355
        # key, tree_details = state._get_entry(0, fileid_utf8=fileid)
356
        # return os.path.join(*key[0:2]).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.
357
358
    @needs_read_lock
359
    def __iter__(self):
360
        """Iterate through file_ids for this tree.
361
362
        file_ids are in a WorkingTree if they are in the working inventory
363
        and the working file exists.
364
        """
365
        result = []
2255.2.88 by Robert Collins
Significant steps back to operation.
366
        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
367
            if tree_details[0][0] in ('a', 'r'): # absent, relocated
2255.2.88 by Robert Collins
Significant steps back to operation.
368
                # 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.
369
                continue
2255.2.88 by Robert Collins
Significant steps back to operation.
370
            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.
371
            if osutils.lexists(path):
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
372
                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.
373
        return iter(result)
374
2255.2.21 by Robert Collins
Add WorkingTree4._last_revision, making workingtree_implementations.test_changes_from pass.
375
    @needs_read_lock
376
    def _last_revision(self):
377
        """See Mutable.last_revision."""
378
        parent_ids = self.current_dirstate().get_parent_ids()
379
        if parent_ids:
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
380
            return parent_ids[0]
2255.2.21 by Robert Collins
Add WorkingTree4._last_revision, making workingtree_implementations.test_changes_from pass.
381
        else:
382
            return None
383
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
384
    def lock_read(self):
385
        super(WorkingTree4, self).lock_read()
386
        if self._dirstate is None:
387
            self.current_dirstate()
388
            self._dirstate.lock_read()
389
390
    def lock_tree_write(self):
391
        super(WorkingTree4, self).lock_tree_write()
392
        if self._dirstate is None:
393
            self.current_dirstate()
394
            self._dirstate.lock_write()
395
396
    def lock_write(self):
397
        super(WorkingTree4, self).lock_write()
398
        if self._dirstate is None:
399
            self.current_dirstate()
400
            self._dirstate.lock_write()
401
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
402
    @needs_tree_write_lock
2255.2.137 by John Arbash Meinel
Move the WorkingTree.move() tests into their own module
403
    def move(self, from_paths, to_dir, after=False):
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
404
        """See WorkingTree.move()."""
405
        if not from_paths:
406
            return ()
407
408
        state = self.current_dirstate()
409
410
        assert not isinstance(from_paths, basestring)
411
        to_dir_utf8 = to_dir.encode('utf8')
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
412
        to_entry_dirname, to_basename = os.path.split(to_dir_utf8)
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
413
        # check destination directory
414
        # get the details for it
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
415
        to_entry_block_index, to_entry_entry_index, dir_present, entry_present = \
416
            state._get_block_entry_index(to_entry_dirname, to_basename, 0)
417
        if not entry_present:
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
418
            raise errors.BzrMoveFailedError('', to_dir,
419
                errors.NotInWorkingDirectory(to_dir))
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
420
        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.
421
        # get a handle on the block itself.
422
        to_block_index = state._ensure_block(
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
423
            to_entry_block_index, to_entry_entry_index, to_dir_utf8)
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
424
        to_block = state._dirblocks[to_block_index]
425
        to_abs = self.abspath(to_dir)
426
        if not isdir(to_abs):
427
            raise errors.BzrMoveFailedError('',to_dir,
428
                errors.NotADirectory(to_abs))
429
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
430
        if to_entry[1][0][0] != 'd':
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
431
            raise errors.BzrMoveFailedError('',to_dir,
432
                errors.NotADirectory(to_abs))
433
434
        if self._inventory is not None:
435
            update_inventory = True
436
            inv = self.inventory
437
            to_dir_ie = inv[to_dir_id]
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
438
            to_dir_id = to_entry[0][2]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
439
        else:
440
            update_inventory = False
441
442
        # create rename entries and tuples
443
        for from_rel in from_paths:
444
            # from_rel is 'pathinroot/foo/bar'
445
            from_dirname, from_tail = os.path.split(from_rel)
446
            from_dirname = from_dirname.encode('utf8')
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
447
            from_entry = self._get_entry(path=from_rel)
448
            if from_entry == (None, None):
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
449
                raise errors.BzrMoveFailedError(from_rel,to_dir,
450
                    errors.NotVersionedError(path=str(from_rel)))
451
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
452
            from_id = from_entry[0][2]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
453
            to_rel = pathjoin(to_dir, from_tail)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
454
            item_to_entry = self._get_entry(path=to_rel)
455
            if item_to_entry != (None, None):
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
456
                raise errors.BzrMoveFailedError(from_rel, to_rel,
457
                    "Target is already versioned.")
458
459
            if from_rel == to_rel:
460
                raise errors.BzrMoveFailedError(from_rel, to_rel,
461
                    "Source and target are identical.")
462
463
            from_missing = not self.has_filename(from_rel)
464
            to_missing = not self.has_filename(to_rel)
465
            if after:
466
                move_file = False
467
            else:
468
                move_file = True
469
            if to_missing:
470
                if not move_file:
471
                    raise errors.BzrMoveFailedError(from_rel, to_rel,
472
                        errors.NoSuchFile(path=to_rel,
473
                        extra="New file has not been created yet"))
474
                elif from_missing:
475
                    # neither path exists
476
                    raise errors.BzrRenameFailedError(from_rel, to_rel,
477
                        errors.PathsDoNotExist(paths=(from_rel, to_rel)))
478
            else:
479
                if from_missing: # implicitly just update our path mapping
480
                    move_file = False
2255.2.139 by John Arbash Meinel
test cases for moving after a file has already been moved.
481
                elif not after:
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
482
                    raise errors.RenameFailedFilesExist(from_rel, to_rel,
483
                        extra="(Use --after to update the Bazaar id)")
484
485
            rollbacks = []
486
            def rollback_rename():
487
                """A single rename has failed, roll it back."""
2255.2.138 by John Arbash Meinel
implement several new WorkingTree.move() tests
488
                exc_info = None
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
489
                for rollback in reversed(rollbacks):
490
                    try:
491
                        rollback()
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
492
                    except Exception, e:
493
                        import pdb;pdb.set_trace()
2255.2.138 by John Arbash Meinel
implement several new WorkingTree.move() tests
494
                        exc_info = sys.exc_info()
495
                if exc_info:
496
                    raise exc_info[0], exc_info[1], exc_info[2]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
497
498
            # 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.
499
            if move_file:
500
                from_rel_abs = self.abspath(from_rel)
501
                to_rel_abs = self.abspath(to_rel)
502
                try:
503
                    osutils.rename(from_rel_abs, to_rel_abs)
504
                except OSError, e:
505
                    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
506
                rollbacks.append(lambda: osutils.rename(to_rel_abs, from_rel_abs))
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
507
            try:
508
                # perform the rename in the inventory next if needed: its easy
509
                # to rollback
510
                if update_inventory:
511
                    # rename the entry
512
                    from_entry = inv[from_id]
513
                    current_parent = from_entry.parent_id
514
                    inv.rename(from_id, to_dir_id, from_tail)
515
                    rollbacks.append(
516
                        lambda: inv.rename(from_id, current_parent, from_tail))
517
                # finally do the rename in the dirstate, which is a little
518
                # tricky to rollback, but least likely to need it.
519
                basename = from_tail.encode('utf8')
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
520
                old_block_index, old_entry_index, dir_present, file_present = \
521
                    state._get_block_entry_index(from_dirname, basename, 0)
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
522
                old_block = state._dirblocks[old_block_index][1]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
523
                old_entry_details = old_block[old_entry_index][1]
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
524
                # remove the old row
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
525
                from_key = old_block[old_entry_index][0]
526
                to_key = ((to_block[0],) + from_key[1:3])
2255.2.142 by John Arbash Meinel
Simplify the update_minimal api a little bit, and document the parameters.
527
                # We must grab old_entry_details here, because _make_absent
528
                # will mark this record as absent and destroy any info we used
529
                # to have
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
530
                minikind = old_entry_details[0][0]
2255.2.140 by John Arbash Meinel
Update tests to ensure basis tree is not modified
531
                state._make_absent(old_block[old_entry_index])
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
532
                rollbacks.append(
533
                    lambda:state.update_minimal(from_key,
2255.2.142 by John Arbash Meinel
Simplify the update_minimal api a little bit, and document the parameters.
534
                        minikind,
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
535
                        executable=old_entry_details[0][3],
536
                        fingerprint=old_entry_details[0][1],
537
                        packed_stat=old_entry_details[0][4],
538
                        size=old_entry_details[0][2],
539
                        id_index=state._get_id_index(),
540
                        path_utf8=from_rel.encode('utf8')))
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
541
                # create new row in current block
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
542
                state.update_minimal(to_key,
2255.2.142 by John Arbash Meinel
Simplify the update_minimal api a little bit, and document the parameters.
543
                        minikind,
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
544
                        executable=old_entry_details[0][3],
545
                        fingerprint=old_entry_details[0][1],
546
                        packed_stat=old_entry_details[0][4],
547
                        size=old_entry_details[0][2],
548
                        id_index=state._get_id_index(),
549
                        path_utf8=to_rel.encode('utf8'))
550
                added_entry_index, _ = state._find_entry_index(to_key, to_block[1])
2255.2.138 by John Arbash Meinel
implement several new WorkingTree.move() tests
551
                new_entry = to_block[1][added_entry_index]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
552
                rollbacks.append(lambda:state._make_absent(new_entry))
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
553
                if new_entry[1][0][0] == 'd':
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
554
                    import pdb;pdb.set_trace()
555
                    # if a directory, rename all the contents of child blocks
556
                    # adding rollbacks as each is inserted to remove them and
557
                    # restore the original
558
                    # TODO: large scale slice assignment.
559
                    # setup new list
560
                    # save old list region
561
                    # move up or down the old region
562
                    # add rollback to move the region back
563
                    # assign new list to new region
564
                    # done
565
            except:
566
                rollback_rename()
567
                raise
568
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
569
            self._dirty = True
570
571
        return #rename_tuples
572
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.
573
    def _new_tree(self):
574
        """Initialize the state in this tree to be a new tree."""
575
        self._dirty = True
576
577
    @needs_read_lock
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
578
    def path2id(self, path):
579
        """Return the id for path in this tree."""
2255.2.88 by Robert Collins
Significant steps back to operation.
580
        entry = self._get_entry(path=path)
581
        if entry == (None, None):
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
582
            return None
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
583
        return entry[0][2]
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
584
2255.2.104 by Robert Collins
Add WorkingTree4.paths2ids which is inventory-usage free if the trees being examined are in the dirstate.
585
    def paths2ids(self, paths, trees=[], require_versioned=True):
586
        """See Tree.paths2ids().
587
        
588
        This specialisation fast-paths the case where all the trees are in the
589
        dirstate.
590
        """
591
        if paths is None:
592
            return None
593
        parents = self.get_parent_ids()
594
        for tree in trees:
595
            if not (isinstance(tree, DirStateRevisionTree) and tree._revision_id in
596
                parents):
597
                return super(WorkingTree4, self).paths2ids(paths, trees, require_versioned)
598
        search_indexes = [0] + [1 + parents.index(tree._revision_id) for tree in trees]
599
        # -- make all paths utf8 --
600
        paths_utf8 = set()
601
        for path in paths:
602
            paths_utf8.add(path.encode('utf8'))
603
        paths = paths_utf8
604
        # -- paths is now a utf8 path set --
605
        # -- get the state object and prepare it.
606
        state = self.current_dirstate()
2255.2.133 by John Arbash Meinel
Implement _paths2ids using bisect recursive rather than loading
607
        if False and (state._dirblock_state == dirstate.DirState.NOT_IN_MEMORY
608
            and '' not in paths):
609
            paths2ids = self._paths2ids_using_bisect
610
        else:
611
            paths2ids = self._paths2ids_in_memory
612
        return paths2ids(paths, search_indexes,
613
                         require_versioned=require_versioned)
614
615
    def _paths2ids_in_memory(self, paths, search_indexes,
616
                             require_versioned=True):
617
        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.
618
        state._read_dirblocks_if_needed()
619
        def _entries_for_path(path):
620
            """Return a list with all the entries that match path for all ids.
621
            """
622
            dirname, basename = os.path.split(path)
623
            key = (dirname, basename, '')
624
            block_index, present = state._find_block_index_from_key(key)
625
            if not present:
626
                # the block which should contain path is absent.
627
                return []
628
            result = []
629
            block = state._dirblocks[block_index][1]
630
            entry_index, _ = state._find_entry_index(key, block)
631
            # we may need to look at multiple entries at this path: walk while the paths match.
632
            while (entry_index < len(block) and
633
                block[entry_index][0][0:2] == key[0:2]):
634
                result.append(block[entry_index])
635
                entry_index += 1
636
            return result
637
        if require_versioned:
638
            # -- check all supplied paths are versioned in all search trees. --
639
            all_versioned = True
640
            for path in paths:
641
                path_entries = _entries_for_path(path)
642
                if not path_entries:
643
                    # this specified path is not present at all: error
644
                    all_versioned = False
645
                    break
646
                found_versioned = False
647
                # for each id at this path
648
                for entry in path_entries:
649
                    # for each tree.
650
                    for index in search_indexes:
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
651
                        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.
652
                            found_versioned = True
653
                            # all good: found a versioned cell
654
                            break
655
                if not found_versioned:
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
656
                    # 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.
657
                    # path.
658
                    all_versioned = False
659
                    break
660
            if not all_versioned:
661
                raise errors.PathsNotVersionedError(paths)
662
        # -- remove redundancy in supplied paths to prevent over-scanning --
663
        search_paths = set()
664
        for path in paths:
665
            other_paths = paths.difference(set([path]))
666
            if not osutils.is_inside_any(other_paths, path):
667
                # this is a top level path, we must check it.
668
                search_paths.add(path)
669
        # sketch: 
670
        # for all search_indexs in each path at or under each element of
671
        # search_paths, if the detail is relocated: add the id, and add the
672
        # relocated path as one to search if its not searched already. If the
673
        # detail is not relocated, add the id.
674
        searched_paths = set()
675
        found_ids = set()
676
        def _process_entry(entry):
677
            """Look at search_indexes within entry.
678
679
            If a specific tree's details are relocated, add the relocation
680
            target to search_paths if not searched already. If it is absent, do
681
            nothing. Otherwise add the id to found_ids.
682
            """
683
            for index in search_indexes:
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
684
                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.
685
                    if not osutils.is_inside_any(searched_paths, entry[1][index][1]):
686
                        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
687
                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.
688
                    found_ids.add(entry[0][2])
689
        while search_paths:
690
            current_root = search_paths.pop()
691
            searched_paths.add(current_root)
692
            # process the entries for this containing directory: the rest will be
693
            # found by their parents recursively.
694
            root_entries = _entries_for_path(current_root)
695
            if not root_entries:
696
                # this specified path is not present at all, skip it.
697
                continue
698
            for entry in root_entries:
699
                _process_entry(entry)
700
            initial_key = (current_root, '', '')
701
            block_index, _ = state._find_block_index_from_key(initial_key)
702
            while (block_index < len(state._dirblocks) and
703
                osutils.is_inside(current_root, state._dirblocks[block_index][0])):
704
                for entry in state._dirblocks[block_index][1]:
705
                    _process_entry(entry)
706
                block_index += 1
707
        return found_ids
708
2255.2.133 by John Arbash Meinel
Implement _paths2ids using bisect recursive rather than loading
709
    def _paths2ids_using_bisect(self, paths, search_indexes,
710
                                require_versioned=True):
711
        state = self.current_dirstate()
712
        found_ids = set()
713
714
        split_paths = sorted(osutils.split(p) for p in paths)
715
        found = state._bisect_recursive(split_paths)
716
717
        if require_versioned:
718
            found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
719
            for dir_name in split_paths:
720
                if dir_name not in found_dir_names:
721
                    raise errors.PathsNotVersionedError(paths)
722
723
        for dir_name_id, trees_info in found.iteritems():
724
            for index in search_indexes:
725
                if trees_info[index][0] not in ('r', 'a'):
726
                    found_ids.add(dir_name_id[2])
727
        return found_ids
728
2255.2.45 by Robert Collins
Dirstate - fix revision_tree() behaviour to match the interface contract.
729
    def read_working_inventory(self):
730
        """Read the working inventory.
731
        
732
        This is a meaningless operation for dirstate, but we obey it anyhow.
733
        """
734
        return self.inventory
735
2255.2.17 by Robert Collins
tweaks - finishes off all the test_test_trees tests for dirstate.
736
    @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.
737
    def revision_tree(self, revision_id):
738
        """See Tree.revision_tree.
739
740
        WorkingTree4 supplies revision_trees for any basis tree.
741
        """
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
742
        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.
743
        dirstate = self.current_dirstate()
744
        parent_ids = dirstate.get_parent_ids()
745
        if revision_id not in parent_ids:
746
            raise errors.NoSuchRevisionInTree(self, revision_id)
2255.2.45 by Robert Collins
Dirstate - fix revision_tree() behaviour to match the interface contract.
747
        if revision_id in dirstate.get_ghosts():
748
            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.
749
        return DirStateRevisionTree(dirstate, revision_id,
750
            self.branch.repository)
751
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
752
    @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.
753
    def set_last_revision(self, new_revision):
754
        """Change the last revision in the working tree."""
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
755
        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.
756
        parents = self.get_parent_ids()
757
        if new_revision in (NULL_REVISION, None):
2255.2.56 by Robert Collins
Dirstate: bring set_last_revision into line with the tested API.
758
            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.
759
                "setting the last parent to none with a pending merge is "
760
                "unsupported.")
761
            self.set_parent_ids([])
762
        else:
2255.2.56 by Robert Collins
Dirstate: bring set_last_revision into line with the tested API.
763
            self.set_parent_ids([new_revision] + parents[1:],
764
                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.
765
766
    @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.
767
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
768
        """Set the parent ids to revision_ids.
769
        
770
        See also set_parent_trees. This api will try to retrieve the tree data
771
        for each element of revision_ids from the trees repository. If you have
772
        tree data already available, it is more efficient to use
773
        set_parent_trees rather than set_parent_ids. set_parent_ids is however
774
        an easier API to use.
775
776
        :param revision_ids: The revision_ids to set as the parent ids of this
777
            working tree. Any of these may be ghosts.
778
        """
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
779
        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.
780
        trees = []
781
        for revision_id in revision_ids:
782
            try:
783
                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
784
                # TODO: jam 20070213 KnitVersionedFile raises
785
                #       RevisionNotPresent rather than NoSuchRevision if a
786
                #       given revision_id is not present. Should Repository be
787
                #       catching it and re-raising NoSuchRevision?
788
            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.
789
                revtree = None
790
            trees.append((revision_id, revtree))
791
        self.set_parent_trees(trees,
792
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
793
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
794
    @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.
795
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
796
        """Set the parents of the working tree.
797
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
798
        :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.
799
            If tree is None, then that element is treated as an unreachable
800
            parent tree - i.e. a ghost.
801
        """
802
        dirstate = self.current_dirstate()
803
        if len(parents_list) > 0:
804
            if not allow_leftmost_as_ghost and parents_list[0][1] is None:
2255.2.42 by Robert Collins
Fix WorkingTree4.set_parent_trees.
805
                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.
806
        real_trees = []
807
        ghosts = []
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
808
        # 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.
809
        # missing on access.
810
        for rev_id, tree in parents_list:
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
811
            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.
812
            if tree is not None:
813
                real_trees.append((rev_id, tree))
814
            else:
815
                real_trees.append((rev_id,
816
                    self.branch.repository.revision_tree(None)))
817
                ghosts.append(rev_id)
818
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
819
        self._dirty = True
820
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
821
    def _set_root_id(self, file_id):
822
        """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.
823
        state = self.current_dirstate()
824
        state.set_path_id('', file_id)
825
        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.
826
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.
827
    def unlock(self):
828
        """Unlock in format 4 trees needs to write the entire dirstate."""
829
        if self._control_files._lock_count == 1:
2255.2.44 by Robert Collins
Fix tree unlock on readonly Format4 trees with dirty hashcache.
830
            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.
831
            # eventually we should do signature checking during read locks for
832
            # dirstate updates.
833
            if self._control_files._lock_mode == 'w':
834
                if self._dirty:
835
                    self.flush()
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
836
            if self._dirstate is not None:
837
                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.
838
            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.
839
            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.
840
        # reverse order of locking.
841
        try:
842
            return self._control_files.unlock()
843
        finally:
844
            self.branch.unlock()
845
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
846
    @needs_tree_write_lock
847
    def unversion(self, file_ids):
848
        """Remove the file ids in file_ids from the current versioned set.
849
850
        When a file_id is unversioned, all of its children are automatically
851
        unversioned.
852
853
        :param file_ids: The file ids to stop versioning.
854
        :raises: NoSuchId if any fileid is not currently versioned.
855
        """
856
        if not file_ids:
857
            return
858
        state = self.current_dirstate()
859
        state._read_dirblocks_if_needed()
860
        ids_to_unversion = set()
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
861
        for file_id in file_ids:
862
            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.
863
        paths_to_unversion = set()
864
        # sketch:
865
        # 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.
866
        # walk the state marking unversioned things as absent.
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
867
        # if there are any un-unversioned ids at the end, raise
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
868
        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
869
            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.
870
                key[2] in ids_to_unversion):
871
                # I haven't written the code to unversion / yet - it should be
872
                # supported.
873
                raise errors.BzrError('Unversioning the / is not currently supported')
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
874
        details_length = len(state._dirblocks[0][1][0][1])
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
875
        block_index = 0
876
        while block_index < len(state._dirblocks):
877
            # process one directory at a time.
878
            block = state._dirblocks[block_index]
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
879
            # first check: is the path one to remove - it or its children
880
            delete_block = False
881
            for path in paths_to_unversion:
882
                if (block[0].startswith(path) and
883
                    (len(block[0]) == len(path) or
884
                     block[0][len(path)] == '/')):
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
885
                    # this entire block should be deleted - its the block for a
886
                    # path to unversion; or the child of one
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
887
                    delete_block = True
888
                    break
889
            # TODO: trim paths_to_unversion as we pass by paths
890
            if delete_block:
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
891
                # this block is to be deleted: process it.
892
                # TODO: we can special case the no-parents case and
893
                # just forget the whole block.
894
                entry_index = 0
895
                while entry_index < len(block[1]):
896
                    if not state._make_absent(block[1][entry_index]):
897
                        entry_index += 1
898
                # go to the next block. (At the moment we dont delete empty
899
                # dirblocks)
900
                block_index += 1
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
901
                continue
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
902
            entry_index = 0
903
            while entry_index < len(block[1]):
904
                entry = block[1][entry_index]
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
905
                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.
906
                    # ^ some parent row.
907
                    entry[0][2] not in ids_to_unversion):
908
                    # ^ not an id to unversion
909
                    entry_index += 1
910
                    continue
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
911
                if entry[1][0][0] == 'd':
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
912
                    paths_to_unversion.add(os.path.join(*entry[0][0:2]))
913
                if not state._make_absent(entry):
914
                    entry_index += 1
915
                # we have unversioned this id
916
                ids_to_unversion.remove(entry[0][2])
917
            block_index += 1
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
918
        if ids_to_unversion:
919
            raise errors.NoSuchId(self, iter(ids_to_unversion).next())
2255.2.46 by Robert Collins
Dirstate - unversion should set the tree state as dirty.
920
        self._dirty = True
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
921
        # have to change the legacy inventory too.
922
        if self._inventory is not None:
923
            for file_id in file_ids:
2255.2.33 by Robert Collins
Correct thunko in refactoring a few commits back.
924
                self._inventory.remove_recursive_id(file_id)
2255.2.22 by Robert Collins
Dirstate: implement WorkingTree4.unversion, letting some test_commit tests pass.
925
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.
926
    @needs_tree_write_lock
927
    def _write_inventory(self, inv):
928
        """Write inventory as the current inventory."""
929
        assert not self._dirty, "attempting to write an inventory when the dirstate is dirty will cause data loss"
930
        self.current_dirstate().set_state_from_inventory(inv)
931
        self._dirty = True
932
        self.flush()
933
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.
934
935
class WorkingTreeFormat4(WorkingTreeFormat3):
936
    """The first consolidated dirstate working tree format.
937
938
    This format:
939
        - exists within a metadir controlling .bzr
940
        - includes an explicit version marker for the workingtree control
941
          files, separate from the BzrDir format
942
        - modifies the hash cache format
943
        - is new in bzr TODO FIXME SETBEFOREMERGE
944
        - uses a LockDir to guard access to it.
945
    """
946
947
    def get_format_string(self):
948
        """See WorkingTreeFormat.get_format_string()."""
949
        return "Bazaar Working Tree format 4\n"
950
951
    def get_format_description(self):
952
        """See WorkingTreeFormat.get_format_description()."""
953
        return "Working tree format 4"
954
955
    def initialize(self, a_bzrdir, revision_id=None):
956
        """See WorkingTreeFormat.initialize().
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
957
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.
958
        revision_id allows creating a working tree at a different
959
        revision than the branch is at.
960
        """
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
961
        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.
962
        if not isinstance(a_bzrdir.transport, LocalTransport):
963
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
964
        transport = a_bzrdir.get_workingtree_transport(self)
965
        control_files = self._open_control_files(a_bzrdir)
966
        control_files.create_lock()
967
        control_files.lock_write()
968
        control_files.put_utf8('format', self.get_format_string())
969
        branch = a_bzrdir.open_branch()
970
        if revision_id is None:
971
            revision_id = branch.last_revision()
972
        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
973
        state = dirstate.DirState.initialize(local_path)
974
        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.
975
        wt = WorkingTree4(a_bzrdir.root_transport.local_abspath('.'),
976
                         branch,
977
                         _format=self,
978
                         _bzrdir=a_bzrdir,
979
                         _control_files=control_files)
980
        wt._new_tree()
981
        wt.lock_write()
982
        try:
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
983
            #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.
984
            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.
985
            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.
986
            basis = wt.basis_tree()
987
            basis.lock_read()
988
            transform.build_tree(basis, wt)
989
            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.
990
        finally:
991
            control_files.unlock()
992
            wt.unlock()
993
        return wt
994
995
996
    def _open(self, a_bzrdir, control_files):
997
        """Open the tree itself.
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
998
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.
999
        :param a_bzrdir: the dir for the tree.
1000
        :param control_files: the control files for the tree.
1001
        """
1002
        return WorkingTree4(a_bzrdir.root_transport.local_abspath('.'),
1003
                           branch=a_bzrdir.open_branch(),
1004
                           _format=self,
1005
                           _bzrdir=a_bzrdir,
1006
                           _control_files=control_files)
1007
1008
1009
class DirStateRevisionTree(Tree):
1010
    """A revision tree pulling the inventory from a dirstate."""
1011
1012
    def __init__(self, dirstate, revision_id, repository):
1013
        self._dirstate = dirstate
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1014
        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.
1015
        self._repository = repository
1016
        self._inventory = None
2255.2.38 by Robert Collins
Fix WorkingTree4.pull to work.
1017
        self._locked = 0
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
1018
        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.
1019
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1020
    def annotate_iter(self, file_id):
1021
        """See Tree.annotate_iter"""
1022
        w = self._repository.weave_store.get_weave(file_id,
1023
                           self._repository.get_transaction())
1024
        return w.annotate_iter(self.inventory[file_id].revision)
1025
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.
1026
    def _comparison_data(self, entry, path):
1027
        """See Tree._comparison_data."""
1028
        if entry is None:
1029
            return None, False, None
1030
        # trust the entry as RevisionTree does, but this may not be
1031
        # sensible: the entry might not have come from us?
1032
        return entry.kind, entry.executable, None
1033
2255.2.10 by Robert Collins
Now all tests matching dirstate pass - added generation of inventories for parent trees.
1034
    def _file_size(self, entry, stat_value):
1035
        return entry.text_size
1036
2255.2.78 by Robert Collins
Really finish the prior commit.
1037
    def filter_unversioned_files(self, paths):
1038
        """Filter out paths that are not versioned.
1039
1040
        :return: set of paths.
1041
        """
1042
        pred = self.has_filename
1043
        return set((p for p in paths if not pred(p)))
1044
2255.2.134 by John Arbash Meinel
Add a tree-test for get_symlink_target
1045
    def _get_parent_index(self):
1046
        """Return the index in the dirstate referenced by this tree."""
1047
        return self._dirstate.get_parent_ids().index(self._revision_id) + 1
1048
2255.2.98 by Robert Collins
Perform path2id lookups in dirstate revision trees from the dirstate index without requiring an inventory.
1049
    def _get_entry(self, file_id=None, path=None):
1050
        """Get the dirstate row for file_id or path.
1051
1052
        If either file_id or path is supplied, it is used as the key to lookup.
1053
        If both are supplied, the fastest lookup is used, and an error is
1054
        raised if they do not both point at the same row.
1055
        
1056
        :param file_id: An optional unicode file_id to be looked up.
1057
        :param path: An optional unicode path to be looked up.
1058
        :return: The dirstate row tuple for path/file_id, or (None, None)
1059
        """
1060
        if file_id is None and path is None:
1061
            raise errors.BzrError('must supply file_id or path')
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1062
        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.
1063
        if path is not None:
1064
            path = path.encode('utf8')
2255.2.134 by John Arbash Meinel
Add a tree-test for get_symlink_target
1065
        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.
1066
        return self._dirstate._get_entry(parent_index, fileid_utf8=file_id, path_utf8=path)
1067
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1068
    def _generate_inventory(self):
1069
        """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.
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
        This is relatively expensive: we have to walk the entire dirstate.
1072
        Ideally we would not, and instead would """
1073
        assert self._locked, 'cannot generate inventory of an unlocked '\
1074
            'dirstate revision tree'
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1075
        # separate call for profiling - makes it clear where the costs are.
1076
        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.
1077
        assert self._revision_id in self._dirstate.get_parent_ids(), \
1078
            'parent %s has disappeared from %s' % (
1079
            self._revision_id, self._dirstate.get_parent_ids())
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1080
        parent_index = self._dirstate.get_parent_ids().index(self._revision_id) + 1
1081
        # This is identical now to the WorkingTree _generate_inventory except
1082
        # for the tree index use.
1083
        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.
1084
        current_id = root_key[2]
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1085
        assert current_entry[parent_index][0] == 'd'
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1086
        inv = Inventory(root_id=current_id, revision_id=self._revision_id)
1087
        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
1088
        # Turn some things into local variables
1089
        minikind_to_kind = dirstate.DirState._minikind_to_kind
1090
        factory = entry_factory
1091
        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()
1092
        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.
1093
        # we could do this straight out of the dirstate; it might be fast
1094
        # 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()
1095
        parent_ies = {'' : inv.root}
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1096
        for block in self._dirstate._dirblocks[1:]: #skip root
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1097
            dirname = block[0]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1098
            try:
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1099
                parent_ie = parent_ies[dirname]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1100
            except KeyError:
1101
                # all the paths in this block are not versioned in this tree
1102
                continue
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1103
            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
1104
                minikind, link_or_sha1, size, executable, revid = entry[parent_index]
1105
                if minikind in ('a', 'r'): # absent, relocated
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1106
                    # not this tree
1107
                    continue
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1108
                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
1109
                name_unicode = utf8_decode(name)[0]
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1110
                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
1111
                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()
1112
                inv_entry = factory[kind](file_id, name_unicode,
1113
                                          parent_ie.file_id)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1114
                inv_entry.revision = revid
1115
                if kind == 'file':
1116
                    inv_entry.executable = executable
1117
                    inv_entry.text_size = size
1118
                    inv_entry.text_sha1 = link_or_sha1
1119
                elif kind == 'directory':
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1120
                    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.
1121
                elif kind == 'symlink':
1122
                    inv_entry.executable = False
1123
                    inv_entry.text_size = size
2255.2.114 by John Arbash Meinel
_get_inventory: 2.09 => 1.93s by tweaking some of the inner _generate_inventory loops
1124
                    inv_entry.symlink_target = utf8_decode(link_or_sha1)[0]
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1125
                else:
1126
                    raise Exception, kind
2255.2.115 by John Arbash Meinel
_get_inventory 1.75s: Directly update the inventory state rather than using inv.add()
1127
                # These checks cost us around 40ms on a 55k entry tree
1128
                assert file_id not in inv_byid
1129
                assert name_unicode not in parent_ie.children
1130
                inv_byid[file_id] = inv_entry
1131
                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.
1132
        self._inventory = inv
1133
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1134
    def get_file_sha1(self, file_id, path=None, stat_value=None):
1135
        # TODO: if path is present, fast-path on that, as inventory
1136
        # might not be present
1137
        ie = self.inventory[file_id]
1138
        if ie.kind == "file":
1139
            return ie.text_sha1
1140
        return None
1141
1142
    def get_file(self, file_id):
1143
        return StringIO(self.get_file_text(file_id))
1144
1145
    def get_file_lines(self, file_id):
1146
        ie = self.inventory[file_id]
1147
        return self._repository.weave_store.get_weave(file_id,
1148
                self._repository.get_transaction()).get_lines(ie.revision)
1149
1150
    def get_file_size(self, file_id):
1151
        return self.inventory[file_id].text_size
1152
1153
    def get_file_text(self, file_id):
1154
        return ''.join(self.get_file_lines(file_id))
1155
2255.2.134 by John Arbash Meinel
Add a tree-test for get_symlink_target
1156
    def get_symlink_target(self, file_id):
1157
        entry = self._get_entry(file_id=file_id)
1158
        parent_index = self._get_parent_index()
1159
        if entry[1][parent_index][0] != 'l':
1160
            return None
1161
        else:
1162
            # At present, none of the tree implementations supports non-ascii
1163
            # symlink targets. So we will just assume that the dirstate path is
1164
            # correct.
1165
            return entry[1][parent_index][1]
1166
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1167
    def get_revision_id(self):
1168
        """Return the revision id for this tree."""
1169
        return self._revision_id
1170
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1171
    def _get_inventory(self):
1172
        if self._inventory is not None:
1173
            return self._inventory
1174
        self._generate_inventory()
1175
        return self._inventory
1176
1177
    inventory = property(_get_inventory,
1178
                         doc="Inventory of this Tree")
1179
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.
1180
    def get_parent_ids(self):
1181
        """The parents of a tree in the dirstate are not cached."""
1182
        return self._repository.get_revision(self._revision_id).parent_ids
1183
2255.2.30 by Robert Collins
Some workingtree_implementations/test_workingtree.py test work - add DirStateRevisionTree.has_filename, locks around appropriate calls in tests.
1184
    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.
1185
        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.
1186
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1187
    def kind(self, file_id):
1188
        return self.inventory[file_id].kind
1189
1190
    def is_executable(self, file_id, path=None):
1191
        ie = self.inventory[file_id]
1192
        if ie.kind != "file":
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
1193
            return None
2255.2.31 by Robert Collins
Work in progress to make merge_inner work with dirstate trees.
1194
        return ie.executable
1195
2255.2.71 by John Arbash Meinel
Add a test for list_files, and implement it for DirStateRevisionTree
1196
    def list_files(self, include_root=False):
1197
        # We use a standard implementation, because DirStateRevisionTree is
1198
        # dealing with one of the parents of the current state
1199
        inv = self._get_inventory()
1200
        entries = inv.iter_entries()
1201
        if self.inventory.root is not None and not include_root:
1202
            entries.next()
1203
        for path, entry in entries:
1204
            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.
1205
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.
1206
    def lock_read(self):
1207
        """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.
1208
        if not self._locked:
1209
            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
1210
            if self._dirstate._lock_token is None:
1211
                self._dirstate.lock_read()
1212
                self._dirstate_locked = True
2255.2.38 by Robert Collins
Fix WorkingTree4.pull to work.
1213
        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.
1214
2255.2.98 by Robert Collins
Perform path2id lookups in dirstate revision trees from the dirstate index without requiring an inventory.
1215
    @needs_read_lock
2255.2.65 by John Arbash Meinel
override path2id because it should be optimized anyway
1216
    def path2id(self, path):
1217
        """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.
1218
        # lookup by path: faster than splitting and walking the ivnentory.
1219
        entry = self._get_entry(path=path)
1220
        if entry == (None, None):
1221
            return None
2255.2.107 by John Arbash Meinel
(working), fix dirstate to use utf8 file ids.
1222
        return entry[0][2]
2255.2.65 by John Arbash Meinel
override path2id because it should be optimized anyway
1223
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
    def unlock(self):
1225
        """Unlock, freeing any cache memory used during the lock."""
1226
        # outside of a lock, the inventory is suspect: release it.
2255.2.38 by Robert Collins
Fix WorkingTree4.pull to work.
1227
        self._locked -=1
1228
        if not self._locked:
1229
            self._inventory = None
2255.5.2 by John Arbash Meinel
(broken) lock and unlock the DirState object when locking and unlocking the Tree itself
1230
            self._locked = 0
1231
            if self._dirstate_locked:
1232
                self._dirstate.unlock()
1233
                self._dirstate_locked = False
2255.2.79 by Robert Collins
Take out repository locks from Dirstate revision trees, to improve file text access performance.
1234
            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
1235
1236
    def walkdirs(self, prefix=""):
1237
        # TODO: jam 20070215 This is the cheap way by cheating and using the
1238
        #       RevisionTree implementation.
1239
        #       This should be cleaned up to use the much faster Dirstate code
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1240
        #       This is a little tricky, though, because the dirstate is
1241
        #       indexed by current path, not by parent path.
1242
        #       So for now, we just build up the parent inventory, and extract
1243
        #       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
1244
        _directory = 'directory'
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1245
        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
1246
        top_id = inv.path2id(prefix)
1247
        if top_id is None:
1248
            pending = []
1249
        else:
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1250
            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
1251
        while pending:
1252
            dirblock = []
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1253
            relpath, file_id = pending.pop()
1254
            # 0 - relpath, 1- file-id
1255
            if relpath:
1256
                relroot = relpath + '/'
2255.2.69 by John Arbash Meinel
Implement annotate_iter, get_revision_id, and walkdirs so that all tree_implementations now pass
1257
            else:
1258
                relroot = ""
1259
            # FIXME: stash the node in pending
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1260
            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
1261
            for name, child in entry.sorted_children():
1262
                toppath = relroot + name
1263
                dirblock.append((toppath, name, child.kind, None,
1264
                    child.file_id, child.kind
1265
                    ))
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1266
            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
1267
            # push the user specified dirs from dirblock
1268
            for dir in reversed(dirblock):
1269
                if dir[2] == _directory:
2255.2.70 by John Arbash Meinel
Minor improvements to DirStateRevisionTree.walkdirs()
1270
                    pending.append((dir[0], dir[4]))
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
1271
1272
1273
class InterDirStateTree(InterTree):
1274
    """Fast path optimiser for changes_from with dirstate trees."""
1275
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1276
    def __init__(self, source, target):
1277
        super(InterDirStateTree, self).__init__(source, target)
1278
        if not InterDirStateTree.is_compatible(source, target):
1279
            raise Exception, "invalid source %r and target %r" % (source, target)
1280
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
1281
    @staticmethod
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1282
    def make_source_parent_tree(source, target):
1283
        """Change the source tree into a parent of the target."""
1284
        revid = source.commit('record tree')
1285
        target.branch.repository.fetch(source.branch.repository, revid)
1286
        target.set_parent_ids([revid])
1287
        return target.basis_tree(), target
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
1288
    _matching_from_tree_format = WorkingTreeFormat4()
1289
    _matching_to_tree_format = WorkingTreeFormat4()
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
1290
    _test_mutable_trees_to_test_trees = make_source_parent_tree
1291
1292
    @needs_read_lock
1293
    def compare(self, want_unchanged=False, specific_files=None,
1294
        extra_trees=None, require_versioned=False, include_root=False):
1295
        """Return the changes from source to target.
1296
1297
        :return: A TreeDelta.
1298
        :param specific_files: An optional list of file paths to restrict the
1299
            comparison to. When mapping filenames to ids, all matches in all
1300
            trees (including optional extra_trees) are used, and all children of
1301
            matched directories are included.
1302
        :param want_unchanged: An optional boolean requesting the inclusion of
1303
            unchanged entries in the result.
1304
        :param extra_trees: An optional list of additional trees to use when
1305
            mapping the contents of specific_files (paths) to file_ids.
1306
        :param require_versioned: An optional boolean (defaults to False). When
1307
            supplied and True all the 'specific_files' must be versioned, or
1308
            a PathsNotVersionedError will be thrown.
1309
        """
1310
        # NB: show_status depends on being able to pass in non-versioned files
1311
        # and report them as unknown
1312
        trees = (self.source,)
1313
        if extra_trees is not None:
1314
            trees = trees + tuple(extra_trees)
1315
        # target is usually the newer tree:
1316
        specific_file_ids = self.target.paths2ids(specific_files, trees,
1317
            require_versioned=require_versioned)
1318
        from bzrlib import delta
1319
        if specific_files and not specific_file_ids:
1320
            # All files are unversioned, so just return an empty delta
1321
            # _compare_trees would think we want a complete delta
1322
            return delta.TreeDelta()
1323
        return delta._compare_trees(self.source, self.target, want_unchanged,
1324
            specific_file_ids, include_root)
2255.2.117 by Robert Collins
Add an InterDirStateTree InterTree optimiser.
1325
1326
    @staticmethod
1327
    def is_compatible(source, target):
1328
        # the target must be a dirstate working tree
1329
        if not isinstance(target, WorkingTree4):
1330
            return False
1331
        # the source must be a revtreee or dirstate rev tree.
1332
        if not isinstance(source,
1333
            (revisiontree.RevisionTree, DirStateRevisionTree)):
1334
            return False
1335
        # the source revid must be in the target dirstate
1336
        if not (source._revision_id == NULL_REVISION or
1337
            source._revision_id in target.get_parent_ids()):
1338
            # TODO: what about ghosts? it may well need to 
1339
            # check for them explicitly.
1340
            return False
1341
        return True
1342
1343
InterTree.register_optimiser(InterDirStateTree)