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