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