/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2255.2.26 by John Arbash Meinel
Use a clearer variable for num_present_parents while reading dirblocks
1
# Copyright (C) 2006, 2007 Canonical Ltd
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
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
1852.13.20 by Robert Collins
Steps toward an object model.
17
"""DirState objects record the state of a directory and its bzr metadata.
18
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
19
Pseudo EBNF grammar for the state file. Fields are separated by NULLs, and
20
lines by NL. The field delimiters are ommitted in the grammar, line delimiters
21
are not - this is done for clarity of reading. All string data is in utf8.
22
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
23
MINIKIND = "f" | "d" | "l" | "a" | "r";
1852.13.20 by Robert Collins
Steps toward an object model.
24
NL = "\n";
25
NULL = "\0";
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
26
WHOLE_NUMBER = {digit}, digit;
27
BOOLEAN = "y" | "n";
28
REVISION_ID = a non-empty utf8 string;
1852.13.20 by Robert Collins
Steps toward an object model.
29
30
dirstate format = header line, full checksum, row count, parent details,
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
31
 ghost_details, entries;
32
header line = "#bazaar dirstate flat format 2", NL;
33
full checksum = "adler32: ", ["-"], WHOLE_NUMBER, NL;
1852.13.20 by Robert Collins
Steps toward an object model.
34
row count = "num_entries: ", digit, NL;
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
35
parent_details = WHOLE NUMBER, {REVISION_ID}* NL;
36
ghost_details = WHOLE NUMBER, {REVISION_ID}*, NL;
37
entries = {entry};
38
entry = entry_key, current_entry_details, {parent_entry_details};
39
entry_key = dirname,  basename, fileid;
40
current_entry_details = common_entry_details, working_entry_details;
41
parent_entry_details = common_entry_details, history_entry_details;
42
common_entry_details = MINIKIND, fingerprint, size, executable
43
working_entry_details = packed_stat
44
history_entry_details = REVISION_ID;
45
executable = BOOLEAN;
46
size = WHOLE_NUMBER;
47
fingerprint = a nonempty utf8 sequence with meaning defined by minikind.
48
49
Given this definition, the following is useful to know:
50
entry (aka row) - all the data for a given key.
51
entry[0]: The key (dirname, basename, fileid)
52
entry[0][0]: dirname
53
entry[0][1]: basename
54
entry[0][2]: fileid
55
entry[1]: The tree(s) data for this path and id combination.
56
entry[1][0]: The current tree
57
entry[1][1]: The second tree
58
59
For an entry for a tree, we have (using tree 0 - current tree) to demonstrate:
60
entry[1][0][0]: kind
61
entry[1][0][1]: fingerprint
62
entry[1][0][2]: size
63
entry[1][0][3]: executable
64
entry[1][0][4]: packed_stat
65
OR (for non tree-0)
66
entry[1][1][4]: revision_id
67
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
68
There may be multiple rows at the root, one per id present in the root, so the
69
in memory root row is now:
70
self._dirblocks[0] -> ('', [entry ...]),
71
and the entries in there are
72
entries[0][0]: ''
73
entries[0][1]: ''
74
entries[0][2]: file_id
75
entries[1][0]: The tree data for the current tree for this fileid at /
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
76
etc.
77
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
78
Kinds:
79
'r' is a relocated entry: This path is not present in this tree with this id,
80
    but the id can be found at another location. The fingerprint is used to
81
    point to the target location.
82
'a' is an absent entry: In that tree the id is not present at this path.
83
'd' is a directory entry: This path in this tree is a directory with the
84
    current file id. There is no fingerprint for directories.
85
'f' is a file entry: As for directory, but its a file. The fingerprint is a
86
    sha1 value.
87
'l' is a symlink entry: As for directory, but a symlink. The fingerprint is the
88
    link target.
89
90
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
91
--- Format 1 had the following different definition: ---
1852.13.20 by Robert Collins
Steps toward an object model.
92
rows = dirname, NULL, basename, NULL, MINIKIND, NULL, fileid_utf8, NULL,
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
93
    WHOLE NUMBER (* size *), NULL, packed stat, NULL, sha1|symlink target, 
1852.13.20 by Robert Collins
Steps toward an object model.
94
    {PARENT ROW}
95
PARENT ROW = NULL, revision_utf8, NULL, MINIKIND, NULL, dirname, NULL,
96
    basename, NULL, WHOLE NUMBER (* size *), NULL, "y" | "n", NULL,
97
    SHA1
98
2255.2.4 by Robert Collins
Snapshot dirstate development
99
PARENT ROW's are emitted for every parent that is not in the ghosts details
100
line. That is, if the parents are foo, bar, baz, and the ghosts are bar, then
101
each row will have a PARENT ROW for foo and baz, but not for bar.
102
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
103
104
In any tree, a kind of 'moved' indicates that the fingerprint field
105
(which we treat as opaque data specific to the 'kind' anyway) has the
106
details for the id of this row in that tree.
107
108
I'm strongly tempted to add a id->path index as well, but I think that
109
where we need id->path mapping; we also usually read the whole file, so
110
I'm going to skip that for the moment, as we have the ability to locate
111
via bisect any path in any tree, and if we lookup things by path, we can
112
accumulate a id->path mapping as we go, which will tend to match what we
113
looked for.
114
115
I plan to implement this asap, so please speak up now to alter/tweak the
116
design - and once we stabilise on this, I'll update the wiki page for
117
it.
118
119
The rationale for all this is that we want fast operations for the
120
common case (diff/status/commit/merge on all files) and extremely fast
121
operations for the less common but still occurs a lot status/diff/commit
122
on specific files). Operations on specific files involve a scan for all
123
the children of a path, *in every involved tree*, which the current
124
format did not accommodate. 
1852.13.20 by Robert Collins
Steps toward an object model.
125
----
126
127
Design priorities:
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
128
 1) Fast end to end use for bzr's top 5 uses cases. (commmit/diff/status/merge/???)
1852.13.20 by Robert Collins
Steps toward an object model.
129
 2) fall back current object model as needed.
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
130
 3) scale usably to the largest trees known today - say 50K entries. (mozilla
131
    is an example of this)
1852.13.20 by Robert Collins
Steps toward an object model.
132
133
134
Locking:
135
 Eventually reuse dirstate objects across locks IFF the dirstate file has not
136
 been modified, but will require that we flush/ignore cached stat-hit data
137
 because we wont want to restat all files on disk just because a lock was
138
 acquired, yet we cannot trust the data after the previous lock was released.
139
140
Memory representation:
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
141
 vector of all directories, and vector of the childen ?
1852.13.20 by Robert Collins
Steps toward an object model.
142
   i.e. 
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
143
     root_entrie = (direntry for root, [parent_direntries_for_root]), 
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
144
     dirblocks = [
1852.13.20 by Robert Collins
Steps toward an object model.
145
     ('', ['data for achild', 'data for bchild', 'data for cchild'])
146
     ('dir', ['achild', 'cchild', 'echild'])
147
     ]
148
    - single bisect to find N subtrees from a path spec
149
    - in-order for serialisation - this is 'dirblock' grouping.
150
    - insertion of a file '/a' affects only the '/' child-vector, that is, to
151
      insert 10K elements from scratch does not generates O(N^2) memoves of a
152
      single vector, rather each individual, which tends to be limited to a 
153
      manageable number. Will scale badly on trees with 10K entries in a 
154
      single directory. compare with Inventory.InventoryDirectory which has
155
      a dictionary for the children. No bisect capability, can only probe for
156
      exact matches, or grab all elements and sorta.
157
    - Whats the risk of error here? Once we have the base format being processed
158
      we should have a net win regardless of optimality. So we are going to 
159
      go with what seems reasonably.
2255.2.4 by Robert Collins
Snapshot dirstate development
160
open questions:
1852.13.20 by Robert Collins
Steps toward an object model.
161
162
maybe we should do a test profile of these core structure - 10K simulated searches/lookups/etc?
163
164
Objects for each row?
165
The lifetime of Dirstate objects is current per lock, but see above for
166
possible extensions. The lifetime of a row from a dirstate is expected to be
167
very short in the optimistic case: which we are optimising for. For instance,
168
subtree status will determine from analysis of the disk data what rows need to
169
be examined at all, and will be able to determine from a single row whether
170
that file has altered or not, so we are aiming to process tens of thousands of
171
entries each second within the dirstate context, before exposing anything to
172
the larger codebase. This suggests we want the time for a single file
173
comparison to be < 0.1 milliseconds. That would give us 10000 paths per second
174
processed, and to scale to 100 thousand we'll another order of magnitude to do
175
that. Now, as the lifetime for all unchanged entries is the time to parse, stat
176
the file on disk, and then immediately discard, the overhead of object creation
177
becomes a significant cost.
178
179
Figures: Creating a tuple from from 3 elements was profiled at 0.0625
180
microseconds, whereas creating a object which is subclassed from tuple was
181
0.500 microseconds, and creating an object with 3 elements and slots was 3
182
microseconds long. 0.1 milliseconds is 100 microseconds, and ideally we'll get
183
down to 10 microseconds for the total processing - having 33% of that be object
184
creation is a huge overhead. There is a potential cost in using tuples within
185
each row which is that the conditional code to do comparisons may be slower
186
than method invocation, but method invocation is known to be slow due to stack
187
frame creation, so avoiding methods in these tight inner loops in unfortunately
188
desirable. We can consider a pyrex version of this with objects in future if
189
desired.
190
191
"""
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
192
193
194
import base64
195
import bisect
196
import cStringIO
197
import os
198
import sha
199
import struct
200
import zlib
201
2255.2.23 by John Arbash Meinel
When parsing the contents, ghosts are not records, so should not be included in the line parsing.
202
from bzrlib import (
203
    errors,
204
    trace,
205
    )
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
206
import bzrlib.inventory
2255.2.58 by Robert Collins
Fix the way we used osutils.normalized_filename in dirstate to support overriding in tests - and document this in the original location it was used.
207
from bzrlib import osutils
2255.2.54 by Robert Collins
Add in non-normalized filename sanity check to dirstate add().
208
from bzrlib.osutils import (
209
    pathjoin,
210
    sha_file,
211
    sha_string,
212
    walkdirs,
213
    )
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
214
215
216
class DirState(object):
217
    """Record directory and metadata state for fast access.
218
219
    A dirstate is a specialised data structure for managing local working
220
    tree state information. Its not yet well defined whether it is platform
221
    specific, and if it is how we detect/parameterise that.
222
    """
223
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
224
    _kind_to_minikind = {'absent':'a', 'file':'f', 'directory':'d', 'relocated':'r', 'symlink':'l'}
225
    _minikind_to_kind = {'a':'absent', 'f':'file', 'd':'directory', 'l':'symlink', 'r':'relocated'}
1852.13.20 by Robert Collins
Steps toward an object model.
226
    _to_yesno = {True:'y', False: 'n'} # TODO profile the performance gain
227
     # of using int conversion rather than a dict here. AND BLAME ANDREW IF
228
     # it is faster.
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
229
2255.3.1 by John Arbash Meinel
Rewrite the inner parsing loop, needs performance testing.
230
    # TODO: jam 20070221 Make sure we handle when there are duplicated records
231
    #       (like when we remove + add the same path, or we have a rename)
232
    # TODO: jam 20070221 Figure out what to do if we have a record that exceeds
233
    #       the BISECT_PAGE_SIZE.
234
    BISECT_PAGE_SIZE = 4096
235
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
236
    NOT_IN_MEMORY = 0
237
    IN_MEMORY_UNMODIFIED = 1
238
    IN_MEMORY_MODIFIED = 2
239
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
240
    # A pack_stat (the x's) that is just noise and will never match the output
241
    # of base64 encode.
2255.2.4 by Robert Collins
Snapshot dirstate development
242
    NULLSTAT = 'x' * 32
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
243
    NULL_PARENT_DETAILS = ('absent', '', 0, False, '')
2255.2.4 by Robert Collins
Snapshot dirstate development
244
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
245
    def __init__(self):
2255.2.4 by Robert Collins
Snapshot dirstate development
246
        """Create a  DirState object.
247
248
        Attributes of note:
249
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
250
        :attr _root_entrie: The root row of the directory/file information,
2255.2.4 by Robert Collins
Snapshot dirstate development
251
            - contains the path to / - '', ''
252
            - kind of 'directory',
253
            - the file id of the root in utf8
254
            - size of 0
255
            - a packed state
256
            - and no sha information.
257
        """
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
258
        # _header_state and _dirblock_state represent the current state
259
        # of the dirstate metadata and the per-row data respectiely.
260
        # NOT_IN_MEMORY indicates that no data is in memory
261
        # IN_MEMORY_UNMODIFIED indicates that what we have in memory
262
        #   is the same as is on disk
263
        # IN_MEMORY_MODIFIED indicates that we have a modified version
264
        #   of what is on disk. 
265
        # In future we will add more granularity, for instance _dirblock_state
266
        # will probably support partially-in-memory as a separate variable,
267
        # allowing for partially-in-memory unmodified and partially-in-memory
268
        # modified states.
269
        self._header_state = DirState.NOT_IN_MEMORY
270
        self._dirblock_state = DirState.NOT_IN_MEMORY
271
        self._dirblocks = []
272
        self._ghosts = []
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
273
        self._parents = []
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
274
        self._state_file=None
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
275
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.
276
    def add(self, path, file_id, kind, stat, link_or_sha1):
2255.2.8 by Robert Collins
First DirState.add() method test passing.
277
        """Add a path to be tracked.
278
279
        :param path: The path within the dirstate - '' is the root, 'foo' is the
280
            path foo within the root, 'foo/bar' is the path bar within foo 
281
            within the root.
282
        :param file_id: The file id of the path being added.
283
        :param kind: The kind of the path.
284
        :param stat: The output of os.lstate for the path.
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.
285
        :param link_or_sha1: The sha value of the file, or the target of a
286
            symlink. '' for directories.
2255.2.8 by Robert Collins
First DirState.add() method test passing.
287
        """
288
        # adding a file:
289
        # find the block its in. 
290
        # find the location in the block.
291
        # check its not there
292
        # add it.
2255.2.54 by Robert Collins
Add in non-normalized filename sanity check to dirstate add().
293
        #------- copied from bzrlib.inventory.make_entry
294
        # --- normalized_filename wants a unicode basename only, so get one.
295
        dirname, basename = os.path.split(path)
2255.2.58 by Robert Collins
Fix the way we used osutils.normalized_filename in dirstate to support overriding in tests - and document this in the original location it was used.
296
        # we dont import normalized_filename directly because we want to be
297
        # able to change the implementation at runtime for tests.
298
        norm_name, can_access = osutils.normalized_filename(basename)
2255.2.54 by Robert Collins
Add in non-normalized filename sanity check to dirstate add().
299
        if norm_name != basename:
300
            if can_access:
301
                basename = norm_name
302
            else:
303
                raise errors.InvalidNormalization(path)
304
        # now that we've normalised, we need the correct utf8 path and 
305
        # dirname and basename elements. This single encode and split should be
306
        # faster than three separate encodes.
307
        utf8path = (dirname + '/' + basename).strip('/').encode('utf8')
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.
308
        dirname, basename = os.path.split(utf8path)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
309
        entry_key = (dirname, basename, file_id.encode('utf8'))
2255.2.54 by Robert Collins
Add in non-normalized filename sanity check to dirstate add().
310
        self._read_dirblocks_if_needed()
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
311
        block_index, present = self._find_block_index_from_key(entry_key)
312
        if not present:
313
            # TODO: This test is not complete - an empty directory, or a
314
            # directory for a parent tree will fool it.
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
315
            # some parent path has not been added - its an error to add this
316
            # child
2255.2.29 by Robert Collins
Change the error raised from Dirstate.add for an unversioned parent path to match the WorkingTree interface.
317
            raise errors.NotVersionedError(path, str(self))
2255.2.8 by Robert Collins
First DirState.add() method test passing.
318
        block = self._dirblocks[block_index][1]
2255.2.43 by Robert Collins
WorkingTree4.add must not require a file to exist to add it when kind etc is given.
319
        if stat is None:
320
            size = 0
321
            packed_stat = DirState.NULLSTAT
322
        else:
323
            size = stat.st_size
324
            packed_stat = pack_stat(stat)
2255.2.75 by Robert Collins
Correct generation of revisiontree inventories to handle out of order parents.
325
        parent_info = self._empty_parent_info()
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.
326
        if kind == 'file':
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
327
            entry_data = entry_key, [
328
                (kind, link_or_sha1, size, False, packed_stat),
329
                ] + parent_info
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.
330
        elif kind == 'directory':
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
331
            entry_data = entry_key, [
332
                (kind, '', 0, False, packed_stat),
333
                ] + parent_info
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.
334
        elif kind == 'symlink':
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
335
            entry_data = entry_key, [
336
                (kind, link_or_sha1, size, False, packed_stat),
337
                ] + parent_info
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
338
        else:
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.
339
            raise errors.BzrError('unknown kind %r' % kind)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
340
        entry_index, present = self._find_entry_index(entry_key, block)
341
        assert not present, "basename %r already added" % basename
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
342
        block.insert(entry_index, entry_data)
2255.2.8 by Robert Collins
First DirState.add() method test passing.
343
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.
344
        if kind == 'directory':
345
           # insert a new dirblock
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
346
           self._ensure_block(block_index, entry_index, utf8path)
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
347
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
2255.2.8 by Robert Collins
First DirState.add() method test passing.
348
2255.2.75 by Robert Collins
Correct generation of revisiontree inventories to handle out of order parents.
349
    def _empty_parent_info(self):
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
350
        return [DirState.NULL_PARENT_DETAILS] * (len(self._parents) -
2255.2.75 by Robert Collins
Correct generation of revisiontree inventories to handle out of order parents.
351
                                                    len(self._ghosts))
352
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
353
    def _ensure_block(self, parent_block_index, parent_row_index, dirname):
354
        """Enssure a block for dirname exists.
355
        
356
        This function exists to let callers which know that there is a
357
        directory dirname ensure that the block for it exists. This block can
358
        fail to exist because of demand loading, or because a directory had no
359
        children. In either case it is not an error. It is however an error to
360
        call this if there is no parent entry for the directory, and thus the
361
        function requires the coordinates of such an entry to be provided.
362
363
        The root row is special cased and can be indicated with a parent block
364
        and row index of -1
365
366
        :param parent_block_index: The index of the block in which dirname's row
367
            exists.
368
        :param parent_row_index: The index in the parent block where the row
369
            exists.
370
        :param dirname: The utf8 dirname to ensure there is a block for.
371
        :return: The index for the block.
372
        """
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
373
        assert dirname != ''
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
374
        # the basename of the directory must be the end of its full name.
375
        if not (parent_block_index == -1 and
376
            parent_block_index == -1 and dirname == ''):
377
            assert dirname.endswith(
378
                self._dirblocks[parent_block_index][1][parent_row_index][0][1])
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
379
        block_index, present = self._find_block_index_from_key((dirname, '', ''))
380
        if not present:
381
            ## In future, when doing partial parsing, this should load and 
382
            # populate the entire block.
383
            self._dirblocks.insert(block_index, (dirname, []))
384
        return block_index
2255.2.59 by Robert Collins
All WorkingTree4 and dirstate tests passing.
385
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
386
    def _entries_to_current_state(self, new_entries):
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
387
        """Load new_entries into self.dirblocks.
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
388
389
        Process new_entries into the current state object, making them the active
390
        state.
391
392
        :param new_entries: A sorted list of entries. This function does not sort
393
            to prevent unneeded overhead when callers have a sorted list already.
394
        :return: Nothing.
395
        """
396
        assert new_entries[0][0][0:2] == ('', ''), \
397
            "Missing root row %r" % new_entries[0][0]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
398
        # The two blocks here are deliberate: the root block and the 
399
        # contents-of-root block.
400
        self._dirblocks = [('', []), ('', [])]
401
        current_block = self._dirblocks[0][1]
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
402
        current_dirname = ''
403
        root_key = ('', '')
404
        for entry in new_entries:
405
            if entry[0][0] != current_dirname:
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
406
                # new block - different dirname
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
407
                current_block = []
2255.2.90 by Robert Collins
Correct DirState._entries_to_current_state to group entries by directory properly.
408
                current_dirname = entry[0][0]
409
                self._dirblocks.append((current_dirname, current_block))
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
410
            elif entry[0][1]:
411
                # this is not a root entry for a tree (it has a basename)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
412
                current_block = self._dirblocks[-1][1]
413
            # append the entry to the current block
414
            current_block.append(entry)
415
    
416
    def _entry_to_line(self, entry):
417
        """Serialize entry to a NULL delimited line ready for _get_output_lines.
418
        
419
        :param entry: An entry_tuple as defined in the module docstring.
420
        """
421
        entire_entry = list(entry[0])
422
        for tree_number, tree_data in enumerate(entry[1]):
423
            # (kind, fingerprint, size, executable, tree_specific_string)
424
            entire_entry.extend(tree_data)
425
            # 3 for the key, 5 for the fields per tree.
426
            tree_offset = 3 + tree_number * 5
427
            # kind
428
            entire_entry[tree_offset + 0] = DirState._kind_to_minikind[tree_data[0]]
429
            # size
430
            entire_entry[tree_offset + 2] = str(tree_data[2])
431
            # executable
432
            entire_entry[tree_offset + 3] = DirState._to_yesno[tree_data[3]]
433
        return '\0'.join(entire_entry)
434
2255.3.1 by John Arbash Meinel
Rewrite the inner parsing loop, needs performance testing.
435
    def _fields_per_row(self):
436
        """How many null separated fields should be in each entry row.
437
438
        Each line now has an extra '\n' field which is not used
439
        so we just skip over it
440
        entry size:
441
            3 fields for the key
442
            + number of fields per tree_data (5) * tree count
443
            + newline
444
         """
445
        tree_count = 1 + self._num_present_parents()
446
        return 3 + 5 * tree_count + 1
447
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
448
    def _find_block(self, key, add_if_missing=False):
449
        """Return the block that key should be present in.
450
451
        :param key: A dirstate entry key.
452
        :return: The block tuple.
453
        """
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
454
        block_index, present = self._find_block_index_from_key(key)
455
        if not present:
2255.2.99 by Robert Collins
Dirstate - fix _find_block to create missing blocks when the parent is versioned in the current tree, and fix handling of relocated entries in _make_absent.
456
            if not add_if_missing:
457
                # check to see if key is versioned itself - we might want to
458
                # add it anyway, because dirs with no entries dont get a
459
                # dirblock at parse time.
460
                # This is an uncommon branch to take: most dirs have children,
461
                # and most code works with versioned paths.
462
                parent_base, parent_name = os.path.split(key[0])
463
                if not self._get_block_entry_index(parent_base, parent_name, 0)[3]:
464
                    # some parent path has not been added - its an error to add
465
                    # this child
466
                    raise errors.NotVersionedError(key[0:2], str(self))
467
            self._dirblocks.insert(block_index, (key[0], []))
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
468
        return self._dirblocks[block_index]
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
469
470
    def _find_block_index_from_key(self, key):
471
        """Find the dirblock index for a key.
472
473
        :return: The block index, True if the block for the key is present.
474
        """
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
475
        if key[0:2] == ('', ''):
476
            return 0, True
477
        block_index = bisect.bisect_left(self._dirblocks, (key[0], []), 1)
478
        # _right returns one-past-where-key is so we have to subtract
479
        # one to use it. we use _right here because there are two
480
        # '' blocks - the root, and the contents of root
481
        # we always have a minimum of 2 in self._dirblocks: root and
482
        # root-contents, and for '', we get 2 back, so this is 
483
        # simple and correct:
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
484
        present = (block_index < len(self._dirblocks) and
2255.2.88 by Robert Collins
Significant steps back to operation.
485
            self._dirblocks[block_index][0] == key[0])
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
486
        return block_index, present
487
488
    def _find_entry_index(self, key, block):
489
        """Find the entry index for a key in a block.
490
491
        :return: The entry index, True if the entry for the key is present.
492
        """
493
        entry_index = bisect.bisect_left(block, (key, []))
494
        present = (entry_index < len(block) and
495
            block[entry_index][0] == key)
496
        return entry_index, present
497
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
498
    @staticmethod
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
499
    def from_tree(tree, dir_state_filename):
1852.13.10 by Robert Collins
Use just the tree api to generate dirstate information.
500
        """Create a dirstate from a bzr Tree.
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
501
502
        :param tree: The tree which should provide parent information and
503
            inventory ids.
504
        """
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
505
        result = DirState.initialize(dir_state_filename)
2255.2.77 by Robert Collins
Tune working inventory generation more: walk the blocks, skipping deleted rows.
506
        tree.lock_read()
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
507
        parent_ids = tree.get_parent_ids()
508
        num_parents = len(parent_ids)
509
        parent_trees = []
510
        for parent_id in parent_ids:
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
511
            parent_trees.append((parent_id, tree.branch.repository.revision_tree(parent_id)))
512
            parent_trees[-1][1].lock_read()
513
        result.set_parent_trees(parent_trees, [])
514
        result.set_state_from_inventory(tree.inventory)
515
516
        for revid, parent in parent_trees:
517
            parent.unlock()
518
        tree.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
519
        return result
520
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
521
    def get_ghosts(self):
522
        """Return a list of the parent tree revision ids that are ghosts."""
523
        self._read_header_if_needed()
524
        return self._ghosts
525
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
526
    def get_lines(self):
527
        """Serialise the entire dirstate to a sequence of lines."""
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
528
        if (self._header_state == DirState.IN_MEMORY_UNMODIFIED and
529
            self._dirblock_state == DirState.IN_MEMORY_UNMODIFIED):
530
            # read whats on disk.
531
            self._state_file.seek(0)
532
            return self._state_file.readlines()
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
533
        lines = []
534
        lines.append(self._get_parents_line(self.get_parent_ids()))
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
535
        lines.append(self._get_ghosts_line(self._ghosts))
1852.13.20 by Robert Collins
Steps toward an object model.
536
        # append the root line which is special cased
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
537
        lines.extend(map(self._entry_to_line, self._iter_entries()))
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
538
        return self._get_output_lines(lines)
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
539
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
540
    def _get_ghosts_line(self, ghost_ids):
541
        """Create a line for the state file for ghost information."""
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
542
        return '\0'.join([str(len(ghost_ids))] + ghost_ids)
543
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
544
    def _get_parents_line(self, parent_ids):
545
        """Create a line for the state file for parents information."""
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
546
        return '\0'.join([str(len(parent_ids))] + parent_ids)
547
2255.3.1 by John Arbash Meinel
Rewrite the inner parsing loop, needs performance testing.
548
    def _get_fields_to_entry(self):
549
        """Get a function which converts entry fields into a entry record.
550
551
        This handles kind, size, and executable, as well as parent records.
552
553
        :return: A function which takes a list of fields, and returns an
554
            appropriate record for storing in memory.
555
        """
556
        # This is intentionally unrolled for performance
557
        num_present_parents = self._num_present_parents()
558
        if num_present_parents == 0:
559
            def fields_to_entry_0_parents(fields, _int=int, _tuple=tuple,
560
                                          _mini_to_kind=self._minikind_to_kind):
561
                path_name_file_id_key = _tuple(fields[:3])
562
                return (path_name_file_id_key, [
563
                    ( # Current tree
564
                        _mini_to_kind[fields[3]], # kind
565
                        fields[4],                # fingerprint
566
                        _int(fields[5]),          # size
567
                        fields[6] == 'y',         # executable
568
                        fields[7],                # packed_stat or revision_id
569
                    )])
570
            return fields_to_entry_0_parents
571
        elif num_present_parents == 1:
572
            def fields_to_entry_1_parent(fields, _int=int, _tuple=tuple,
573
                                         _mini_to_kind=self._minikind_to_kind):
574
                path_name_file_id_key = _tuple(fields[:3])
575
                return (path_name_file_id_key, [
576
                    ( # Current tree
577
                        _mini_to_kind[fields[3]], # kind
578
                        fields[4],                # fingerprint
579
                        _int(fields[5]),          # size
580
                        fields[6] == 'y',         # executable
581
                        fields[7],                # packed_stat or revision_id
582
                    ),
583
                    ( # Parent 1
584
                        _mini_to_kind[fields[8]], # kind
585
                        fields[9],                # fingerprint
586
                        _int(fields[10]),         # size
587
                        fields[11] == 'y',        # executable
588
                        fields[12],               # packed_stat or revision_id
589
                    ),
590
                    ])
591
            return fields_to_entry_1_parent
592
        elif num_present_parents == 2:
593
            def fields_to_entry_2_parents(fields, _int=int, _tuple=tuple,
594
                                          _mini_to_kind=self._minikind_to_kind):
595
                path_name_file_id_key = _tuple(fields[:3])
596
                return (path_name_file_id_key, [
597
                    ( # Current tree
598
                        _mini_to_kind[fields[3]], # kind
599
                        fields[4],                # fingerprint
600
                        _int(fields[5]),          # size
601
                        fields[6] == 'y',         # executable
602
                        fields[7],                # packed_stat or revision_id
603
                    ),
604
                    ( # Parent 1
605
                        _mini_to_kind[fields[8]], # kind
606
                        fields[9],                # fingerprint
607
                        _int(fields[10]),         # size
608
                        fields[11] == 'y',        # executable
609
                        fields[12],               # packed_stat or revision_id
610
                    ),
611
                    ( # Parent 2
612
                        _mini_to_kind[fields[13]],# kind
613
                        fields[14],               # fingerprint
614
                        _int(fields[15]),         # size
615
                        fields[16] == 'y',        # executable
616
                        fields[17],               # packed_stat or revision_id
617
                    ),
618
                    ])
619
            return fields_to_entry_2_parents
620
        else:
621
            def fields_to_entry_n_parents(fields, _int=int, _tuple=tuple,
622
                                          _mini_to_kind=self._minikind_to_kind):
623
                path_name_file_id_key = _tuple(fields[:3])
624
                trees = [(_mini_to_kind[fields[cur]], # kind
625
                          fields[cur+1],              # fingerprint
626
                          _int(fields[cur+2]),        # size
627
                          fields[cur+3] == 'y',       # executable
628
                          fields[cur+4],              # stat or revision_id
629
                         ) for cur in xrange(3, len(fields)-1, 5)]
630
                return path_name_file_id_key, trees
631
            return fields_to_entry_n_parents
632
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
633
    def get_parent_ids(self):
634
        """Return a list of the parent tree ids for the directory state."""
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
635
        self._read_header_if_needed()
2255.2.41 by Robert Collins
Fix Dirstate.get_parent_ids to return a copy of the ids, not a list whose mutation will break us.
636
        return list(self._parents)
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
637
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
638
    def _get_block_entry_index(self, dirname, basename, tree_index):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
639
        """Get the coordinates for a path in the state structure.
640
641
        :param dirname: The utf8 dirname to lookup.
642
        :param basename: The utf8 basename to lookup.
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
643
        :param tree_index: The index of the tree for which this lookup should
644
            be attempted.
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
645
        :return: A tuple describing where the path is located, or should be
646
            inserted. The tuple contains four fields: the block index, the row
647
            index, anda two booleans are True when the directory is present, and
648
            when the entire path is present.  There is no guarantee that either
649
            coordinate is currently reachable unless the found field for it is
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
650
            True. For instance, a directory not present in the searched tree
651
            may be returned with a value one greater than the current highest
652
            block offset. The directory present field will always be True when
653
            the path present field is True. The directory present field does
654
            NOT indicate that the directory is present in the searched tree,
655
            rather it indicates that there are at least some files in some
656
            tree present there.
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
657
        """
658
        self._read_dirblocks_if_needed()
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
659
        key = dirname, basename, ''
660
        block_index, present = self._find_block_index_from_key(key)
661
        if not present:
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
662
            # no such directory - return the dir index and 0 for the row.
663
            return block_index, 0, False, False
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
664
        block = self._dirblocks[block_index][1] # access the entries only
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
665
        entry_index, present = self._find_entry_index(key, block)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
666
        # linear search through present entries at this path to find the one
667
        # requested.
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
668
        while entry_index < len(block) and block[entry_index][0][1] == basename:
669
            if block[entry_index][1][tree_index][0] not in \
2255.2.91 by James Westby
Correct the mistakes in the logic of _get_block_entry_index.
670
                       ('absent', 'relocated'):
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
671
                return block_index, entry_index, True, True
672
            entry_index += 1
673
        return block_index, entry_index, True, False
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
674
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
675
    def _get_entry(self, tree_index, fileid_utf8=None, path_utf8=None):
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
676
        """Get the dirstate entry for path in tree tree_index
677
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
678
        If either file_id or path is supplied, it is used as the key to lookup.
679
        If both are supplied, the fastest lookup is used, and an error is
680
        raised if they do not both point at the same row.
681
        
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
682
        :param tree_index: The index of the tree we wish to locate this path
683
            in. If the path is present in that tree, the entry containing its
684
            details is returned, otherwise (None, None) is returned
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
685
        :param fileid_utf8: A utf8 file_id to look up.
686
        :param path_utf8: An utf8 path to be looked up.
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
687
        :return: The dirstate entry tuple for path, or (None, None)
688
        """
2255.2.94 by Robert Collins
DirState: handle id lookup redirects correctly.
689
        self._read_dirblocks_if_needed()
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
690
        if path_utf8 is not None:
691
            assert path_utf8.__class__ == str, 'path_utf8 is not a str: %s %s' % (type(path_utf8), path_utf8)
692
            # path lookups are faster
693
            dirname, basename = os.path.split(path_utf8)
694
            block_index, entry_index, dir_present, file_present = \
695
                self._get_block_entry_index(dirname, basename, tree_index)
696
            if not file_present:
697
                return None, None
698
            entry = self._dirblocks[block_index][1][entry_index]
699
            assert entry[0][2] and entry[1][tree_index][0] not in ('absent', 'relocated'), 'unversioned entry?!?!'
700
            if fileid_utf8:
701
                if entry[0][2] != fileid_utf8:
702
                    raise BzrError('integrity error ? : mismatching tree_index, file_id and path')
703
            return entry
704
        else:
705
            for entry in self._iter_entries():
706
                if entry[0][2] == fileid_utf8:
707
                    if entry[1][tree_index][0] == 'relocated':
708
                        # look up the real location directly by path
709
                        return self._get_entry(tree_index,
710
                            fileid_utf8=fileid_utf8,
2255.2.94 by Robert Collins
DirState: handle id lookup redirects correctly.
711
                            path_utf8=entry[1][tree_index][1])
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
712
                    if entry[1][tree_index][0] == 'absent':
713
                        # not in the tree at all.
714
                        return None, None
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
715
                    return entry
716
            return None, None
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
717
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
718
    @staticmethod
719
    def initialize(path):
1852.13.20 by Robert Collins
Steps toward an object model.
720
        """Create a new dirstate on path.
721
722
        The new dirstate will be an empty tree - that is it has no parents,
723
        and only a root node - which has id ROOT_ID.
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
724
1852.13.20 by Robert Collins
Steps toward an object model.
725
        :param path: The name of the file for the dirstate.
726
        :return: A DirState object.
727
        """
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
728
        # This constructs a new DirState object on a path, sets the _state_file
1852.13.20 by Robert Collins
Steps toward an object model.
729
        # to a new empty file for that path. It then calls _set_data() with our
730
        # stock empty dirstate information - a root with ROOT_ID, no children,
731
        # and no parents. Finally it calls save() to ensure that this data will
732
        # persist.
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
733
        result = DirState()
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
734
        result._state_file = open(path, 'wb+')
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
735
        # root dir and root dir contents with no children.
736
        empty_tree_dirblocks = [('', []), ('', [])]
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
737
        # a new root directory, with a NULLSTAT.
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
738
        empty_tree_dirblocks[0][1].append(
739
            (('', '', bzrlib.inventory.ROOT_ID), [
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
740
                ('directory', '', 0, False, DirState.NULLSTAT),
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
741
            ]))
742
        result._set_data([], empty_tree_dirblocks)
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
743
        try:
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
744
            result.save()
745
        except:
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
746
            result._state_file.close()
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
747
            raise
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
748
        return result
749
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
750
    def _inv_entry_to_details(self, inv_entry):
751
        """Convert an inventory entry (from a revision tree) to state details.
752
753
        :param inv_entry: An inventory entry whose sha1 and link targets can be
754
            relied upon, and which has a revision set.
755
        :return: A details tuple - the details for a single tree at a path +
756
            id.
757
        """
758
        kind = inv_entry.kind
759
        tree_data = inv_entry.revision.encode('utf8')
760
        assert len(tree_data) > 0, 'empty revision for the inv_entry.'
761
        if kind == 'directory':
762
            fingerprint = ''
763
            size = 0
764
            executable = False
765
        elif kind == 'symlink':
766
            fingerprint = inv_entry.symlink_target or ''
767
            size = 0
768
            executable = False
769
        elif kind == 'file':
770
            fingerprint = inv_entry.text_sha1 or ''
771
            size = inv_entry.text_size or 0
772
            executable = inv_entry.executable
773
        else:
774
            raise Exception
775
        return (kind, fingerprint, size, executable, tree_data)
776
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
777
    def _iter_entries(self):
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
778
        """Iterate over all the entries in the dirstate.
779
780
        Each yelt item is an entry in the standard format described in the
781
        docstring of bzrlib.dirstate.
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
782
        """
783
        self._read_dirblocks_if_needed()
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
784
        for directory in self._dirblocks:
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
785
            for entry in directory[1]:
786
                yield entry
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
787
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
788
    def _get_id_index(self):
789
        """Get an id index of self._dirblocks."""
790
        id_index = {}
791
        for key, tree_details in self._iter_entries():
792
            id_index.setdefault(key[2], set()).add(key)
793
        return id_index
794
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
795
    def _get_output_lines(self, lines):
796
        """format lines for final output.
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
797
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
798
        :param lines: A sequece of lines containing the parents list and the
799
            path lines.
800
        """
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
801
        output_lines = ['#bazaar dirstate flat format 2\n']
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
802
        lines.append('') # a final newline
803
        inventory_text = '\0\n\0'.join(lines)
804
        output_lines.append('adler32: %s\n' % (zlib.adler32(inventory_text),))
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
805
        # -3, 1 for num parents, 1 for ghosts, 1 for final newline
806
        num_entries = len(lines)-3
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
807
        output_lines.append('num_entries: %s\n' % (num_entries,))
808
        output_lines.append(inventory_text)
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
809
        return output_lines
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
810
2255.2.36 by Robert Collins
Fix Dirstate unversioning of entries which are in a parent.
811
    def _make_deleted_row(self, fileid_utf8, parents):
812
        """Return a deleted for for fileid_utf8."""
813
        return ('/', 'RECYCLED.BIN', 'file', fileid_utf8, 0, DirState.NULLSTAT,
814
            ''), parents
815
2255.3.1 by John Arbash Meinel
Rewrite the inner parsing loop, needs performance testing.
816
    def _num_present_parents(self):
817
        """The number of parent entries in each record row."""
818
        return len(self._parents) - len(self._ghosts)
819
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
820
    @staticmethod
821
    def on_file(path):
822
        """Construct a DirState on the file at path path."""
823
        result = DirState()
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
824
        result._state_file = open(path, 'rb+')
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
825
        return result
826
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
827
    def _read_dirblocks_if_needed(self):
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
828
        """Read in all the dirblocks from the file if they are not in memory.
829
        
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
830
        This populates self._dirblocks, and sets self._dirblock_state to
831
        IN_MEMORY_UNMODIFIED. It is not currently ready for incremental block
832
        loading.
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
833
        """
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
834
        self._read_header_if_needed()
835
        if self._dirblock_state == DirState.NOT_IN_MEMORY:
836
            # the _state_file pointer will be positioned at the start of the 
837
            # dirblocks.
838
            text = self._state_file.read()
839
            # TODO: check the adler checksums. adler_measured = zlib.adler32(text)
840
841
            fields = text.split('\0')
842
            # Remove the last blank entry
843
            trailing = fields.pop()
844
            assert trailing == ''
845
            # consider turning fields into a tuple.
846
847
            # skip the first field which is the trailing null from the header.
848
            cur = 1
849
            # Each line now has an extra '\n' field which is not used
850
            # so we just skip over it
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
851
            # entry size:
852
            #  3 fields for the key
853
            #  + number of fields per tree_data (5) * tree count
2255.2.26 by John Arbash Meinel
Use a clearer variable for num_present_parents while reading dirblocks
854
            #  + newline
2255.3.1 by John Arbash Meinel
Rewrite the inner parsing loop, needs performance testing.
855
            num_present_parents = self._num_present_parents()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
856
            tree_count = 1 + num_present_parents
2255.3.1 by John Arbash Meinel
Rewrite the inner parsing loop, needs performance testing.
857
            entry_size = self._fields_per_row()
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
858
            expected_field_count = entry_size * self._num_entries
2255.2.32 by Robert Collins
Make test_clear_merge_conflicts pass for dirstate. This involved working
859
            if len(fields) - cur > expected_field_count:
860
                fields = fields[:expected_field_count + cur]
861
                trace.mutter('Unexpectedly long dirstate field count!')
862
                print "XXX: incorrectly truncated dirstate file bug triggered."
863
            field_count = len(fields)
864
            # this checks our adjustment, and also catches file too short.
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
865
            assert field_count - cur == expected_field_count, \
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.
866
                'field count incorrect %s != %s, entry_size=%s, '\
867
                'num_entries=%s fields=%r' % (
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
868
                    field_count - cur, expected_field_count, entry_size,
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.
869
                    self._num_entries, fields)
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
870
2255.3.1 by John Arbash Meinel
Rewrite the inner parsing loop, needs performance testing.
871
            fields_to_entry = self._get_fields_to_entry()
872
            entries = [fields_to_entry(fields[pos:pos+entry_size])
873
                       for pos in xrange(cur, field_count, entry_size)]
874
            self._entries_to_current_state(entries)
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
875
            self._dirblock_state = DirState.IN_MEMORY_UNMODIFIED
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
876
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
877
    def _read_header(self):
878
        """This reads in the metadata header, and the parent ids.
879
880
        After reading in, the file should be positioned at the null
881
        just before the start of the first record in the file.
882
883
        :return: (expected adler checksum, number of entries, parent list)
884
        """
885
        self._read_prelude()
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
886
        parent_line = self._state_file.readline()
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
887
        info = parent_line.split('\0')
888
        num_parents = int(info[0])
889
        assert num_parents == len(info)-2, 'incorrect parent info line'
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
890
        self._parents = info[1:-1]
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
891
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
892
        ghost_line = self._state_file.readline()
893
        info = ghost_line.split('\0')
894
        num_ghosts = int(info[1])
895
        assert num_ghosts == len(info)-3, 'incorrect ghost info line'
2255.2.84 by John Arbash Meinel
Remove now-unecessary encode/decode calls for revision ids.
896
        self._ghosts = info[2:-1]
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
897
        self._header_state = DirState.IN_MEMORY_UNMODIFIED
898
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
899
    def _read_header_if_needed(self):
900
        """Read the header of the dirstate file if needed."""
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
901
        if self._header_state == DirState.NOT_IN_MEMORY:
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
902
            self._read_header()
903
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
904
    def _read_prelude(self):
905
        """Read in the prelude header of the dirstate file
906
907
        This only reads in the stuff that is not connected to the adler
908
        checksum. The position will be correct to read in the rest of
909
        the file and check the checksum after this point.
910
        The next entry in the file should be the number of parents,
911
        and their ids. Followed by a newline.
912
        """
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
913
        header = self._state_file.readline()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
914
        assert header == '#bazaar dirstate flat format 2\n', \
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
915
            'invalid header line: %r' % (header,)
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
916
        adler_line = self._state_file.readline()
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
917
        assert adler_line.startswith('adler32: '), 'missing adler32 checksum'
918
        self.adler_expected = int(adler_line[len('adler32: '):-1])
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
919
        num_entries_line = self._state_file.readline()
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
920
        assert num_entries_line.startswith('num_entries: '), 'missing num_entries line'
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
921
        self._num_entries = int(num_entries_line[len('num_entries: '):-1])
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
922
    
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
923
    def save(self):
2255.2.32 by Robert Collins
Make test_clear_merge_conflicts pass for dirstate. This involved working
924
        """Save any pending changes created during this session.
925
        
926
        We reuse the existing file, because that prevents race conditions with
927
        file creation, and we expect to be using oslocks on it in the near 
928
        future to prevent concurrent modification and reads - because dirstates
929
        incremental data aggretation is not compatible with reading a modified
930
        file, and replacing a file in use by another process is impossible on 
931
        windows.
932
933
        A dirstate in read only mode should be smart enough though to validate
934
        that the file has not changed, and otherwise discard its cache and
935
        start over, to allow for fine grained read lock duration, so 'status'
936
        wont block 'commit' - for example.
937
        """
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
938
        if (self._header_state == DirState.IN_MEMORY_MODIFIED or
939
            self._dirblock_state == DirState.IN_MEMORY_MODIFIED):
940
            self._state_file.seek(0)
941
            self._state_file.writelines(self.get_lines())
2255.2.32 by Robert Collins
Make test_clear_merge_conflicts pass for dirstate. This involved working
942
            self._state_file.truncate()
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
943
            self._state_file.flush()
944
            self._header_state = DirState.IN_MEMORY_UNMODIFIED
945
            self._dirblock_state = DirState.IN_MEMORY_UNMODIFIED
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
946
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
947
    def _set_data(self, parent_ids, dirblocks):
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
948
        """Set the full dirstate data in memory.
1852.13.20 by Robert Collins
Steps toward an object model.
949
950
        This is an internal function used to completely replace the objects
951
        in memory state. It puts the dirstate into state 'full-dirty'.
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
952
953
        :param parent_ids: A list of parent tree revision ids.
954
        :param dirblocks: A list containing one tuple for each directory in the
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
955
            tree. Each tuple contains the directory path and a list of entries 
956
            found in that directory.
1852.13.20 by Robert Collins
Steps toward an object model.
957
        """
958
        # our memory copy is now authoritative.
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
959
        self._dirblocks = dirblocks
960
        self._header_state = DirState.IN_MEMORY_MODIFIED
961
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
962
        self._parents = list(parent_ids)
963
2255.2.4 by Robert Collins
Snapshot dirstate development
964
    def set_path_id(self, path, new_id):
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
965
        """Change the id of path to new_id in the current working tree.
2255.2.4 by Robert Collins
Snapshot dirstate development
966
967
        :param path: The path inside the tree to set - '' is the root, 'foo'
968
            is the path foo in the root.
969
        :param new_id: The new id to assign to the path. If unicode, it will
970
            be encoded to utf8. In future this will be deprecated: avoid using
971
            unicode ids if possible.
972
        """
2255.2.37 by Robert Collins
Get TestExecutable.test_06_pull working on DirState: fix cloning and the set_last_revision api on WorkingTree4.
973
        # TODO: start warning here.
974
        if new_id.__class__ == unicode:
975
            new_id = new_id.encode('utf8')
976
        self._read_dirblocks_if_needed()
2255.2.75 by Robert Collins
Correct generation of revisiontree inventories to handle out of order parents.
977
        if len(path):
978
            import pdb;pdb.set_trace()
979
            # logic not written
980
            raise NotImplementedError(self.set_path_id)
981
        # TODO: check new id is unique
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
982
        entry = self._get_entry(0, path_utf8=path)
983
        # mark the old path absent, and insert a new root path
984
        present_parents = len(entry[1]) - 1
985
        self._make_absent(entry)
986
        id_index = self._get_id_index()
987
        self.update_minimal(('', '', new_id), 'directory', present_parents,
988
            path_utf8='', id_index=id_index, packed_stat=entry[1][0][4])
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
989
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
2255.2.4 by Robert Collins
Snapshot dirstate development
990
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
991
    def set_parent_trees(self, trees, ghosts):
992
        """Set the parent trees for the dirstate.
993
994
        :param trees: A list of revision_id, tree tuples. tree must be provided
995
            even if the revision_id refers to a ghost: supply an empty tree in 
996
            this case.
997
        :param ghosts: A list of the revision_ids that are ghosts at the time
998
            of setting.
999
        """ 
2255.2.4 by Robert Collins
Snapshot dirstate development
1000
        # TODO: generate a list of parent indexes to preserve to save 
1001
        # processing specific parent trees. In the common case one tree will
1002
        # be preserved - the left most parent.
1003
        # TODO: if the parent tree is a dirstate, we might want to walk them
1004
        # all by path in parallel for 'optimal' common-case performance.
1005
        # generate new root row.
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
1006
        self._read_dirblocks_if_needed()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1007
        # TODO future sketch: Examine the existing parents to generate a change
1008
        # map and then walk the new parent trees only, mapping them into the
1009
        # dirstate. Walk the dirstate at the same time to remove unreferenced
1010
        # entries.
1011
        # for now: 
1012
        # sketch: loop over all entries in the dirstate, cherry picking 
1013
        # entries from the parent trees, if they are not ghost trees.
2255.2.4 by Robert Collins
Snapshot dirstate development
1014
        # after we finish walking the dirstate, all entries not in the dirstate
1015
        # are deletes, so we want to append them to the end as per the design
1016
        # discussions. So do a set difference on ids with the parents to
1017
        # get deletes, and add them to the end.
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1018
        # During the update process we need to answer the following questions:
1019
        # - find other keys containing a fileid in order to create cross-path
1020
        #   links. We dont't trivially use the inventory from other trees
1021
        #   because this leads to either double touching, or to accessing
1022
        #   missing keys,
1023
        # - find other keys containing a path 
1024
        # We accumulate each entry via this dictionary, including the root 
1025
        by_path = {}
1026
        id_index = {}
1027
        # we could do parallel iterators, but because file id data may be
1028
        # scattered throughout, we dont save on index overhead: we have to look
1029
        # at everything anyway. We can probably save cycles by reusing parent
1030
        # data and doing an incremental update when adding an additional
1031
        # parent, but for now the common cases are adding a new parent (merge),
1032
        # and replacing completely (commit), and commit is more common: so
1033
        # optimise merge later.
1034
        
1035
        # ---- start generation of full tree mapping data
1036
        # what trees should we use?
2255.2.4 by Robert Collins
Snapshot dirstate development
1037
        parent_trees = [tree for rev_id, tree in trees if rev_id not in ghosts]
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1038
        # how many trees do we end up with 
1039
        parent_count = len(parent_trees)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1040
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1041
        # one: the current tree
1042
        for entry in self._iter_entries():
1043
            # skip entries not in the current tree
1044
            if entry[1][0][0] in ('absent', 'relocated'):
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1045
                continue
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1046
            by_path[entry[0]] = [entry[1][0]] + \
1047
                [DirState.NULL_PARENT_DETAILS] * parent_count
1048
            id_index[entry[0][2]] = set([entry[0]])
1049
        
1050
        # now the parent trees:
1051
        for tree_index, tree in enumerate(parent_trees):
1052
            # the index is off by one, adjust it.
1053
            tree_index = tree_index + 1
1054
            # when we add new locations for a fileid we need these ranges for
1055
            # any fileid in this tree as we set the by_path[id] to:
1056
            # already_processed_tree_details + new_details + new_location_suffix
1057
            # the suffix is from tree_index+1:parent_count+1.
1058
            new_location_suffix = [DirState.NULL_PARENT_DETAILS] * (parent_count - tree_index)
1059
            # now stitch in all the entries from this tree
1060
            for path, entry in tree.inventory.iter_entries_by_dir():
1061
                # here we process each trees details for each item in the tree.
1062
                # we first update any existing entries for the id at other paths,
1063
                # then we either create or update the entry for the id at the
1064
                # right path, and finally we add (if needed) a mapping from
1065
                # file_id to this path. We do it in this order to allow us to
1066
                # avoid checking all known paths for the id when generating a
1067
                # new entry at this path: by adding the id->path mapping last,
1068
                # all the mappings are valid and have correct relocation
1069
                # records where needed. 
1070
                file_id = entry.file_id.encode('utf8')
1071
                path_utf8 = path.encode('utf8')
1072
                dirname, basename = os.path.split(path_utf8)
1073
                new_entry_key = (dirname, basename, file_id)
1074
                # tree index consistency: All other paths for this id in this tree
1075
                # index must point to the correct path.
1076
                for entry_key in id_index.setdefault(file_id, set()):
1077
                    # TODO:PROFILING: It might be faster to just update
1078
                    # rather than checking if we need to, and then overwrite
1079
                    # the one we are located at.
1080
                    if entry_key != new_entry_key:
1081
                        # this file id is at a different path in one of the
1082
                        # other trees, so put absent pointers there
1083
                        # This is the vertical axis in the matrix, all pointing
1084
                        # tot he real path.
1085
                        by_path[entry_key][tree_index] = ('relocated', path_utf8, 0, False, '')
1086
                # by path consistency: Insert into an existing path record (trivial), or 
1087
                # add a new one with relocation pointers for the other tree indexes.
1088
                if new_entry_key in id_index[file_id]:
1089
                    # there is already an entry where this data belongs, just insert it.
1090
                    by_path[new_entry_key][tree_index] = \
1091
                        self._inv_entry_to_details(entry)
1092
                else:
1093
                    # add relocated entries to the horizontal axis - this row
1094
                    # mapping from path,id. We need to look up the correct path
1095
                    # for the indexes from 0 to tree_index -1
1096
                    new_details = []
1097
                    for lookup_index in xrange(tree_index):
1098
                        # boundary case: this is the first occurence of file_id
1099
                        # so there are no id_indexs, possibly take this out of
1100
                        # the loop?
1101
                        if not len(id_index[file_id]):
1102
                            new_details.append(DirState.NULL_PARENT_DETAILS)
1103
                        else:
1104
                            # grab any one entry, use it to find the right path.
1105
                            # TODO: optimise this to reduce memory use in highly 
1106
                            # fragmented situations by reusing the relocation
1107
                            # records.
1108
                            a_key = iter(id_index[file_id]).next()
1109
                            if by_path[a_key][lookup_index][0] in ('relocated', 'absent'):
1110
                                # its a pointer or missing statement, use it as is.
1111
                                new_details.append(by_path[a_key][lookup_index])
1112
                            else:
1113
                                # we have the right key, make a pointer to it.
1114
                                real_path = ('/'.join(a_key[0:2])).strip('/')
1115
                                new_details.append(('relocated', real_path, 0, False, ''))
1116
                    new_details.append(self._inv_entry_to_details(entry))
1117
                    new_details.extend(new_location_suffix)
1118
                    by_path[new_entry_key] = new_details
1119
                    id_index[file_id].add(new_entry_key)
1120
        # --- end generation of full tree mappings
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
1121
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1122
        # sort and output all the entries
1123
        new_entries = sorted(by_path.items())
1124
        self._entries_to_current_state(new_entries)
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
1125
        self._parents = [rev_id for rev_id, tree in trees]
1126
        self._ghosts = list(ghosts)
1127
        self._header_state = DirState.IN_MEMORY_MODIFIED
1128
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1852.13.20 by Robert Collins
Steps toward an object model.
1129
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.
1130
    def set_state_from_inventory(self, new_inv):
1131
        """Set new_inv as the current state. 
1132
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1133
        This API is called by tree transform, and will usually occur with
1134
        existing parent trees.
1135
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.
1136
        :param new_inv: The inventory object to set current state from.
1137
        """
1138
        self._read_dirblocks_if_needed()
1139
        # sketch:
1140
        #  generate a byid index of the dirstate
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1141
        id_index = self._get_id_index()
2255.2.49 by John Arbash Meinel
set_state_from_inventory needs to include NULL records for parents when there wasn't an entry before
1142
1143
        num_present_parents = len(self._parents) - len(self._ghosts)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1144
        # incremental algorithm:
1145
        # two iterators: current data and new data, both in dirblock order. 
1146
        new_iterator = new_inv.iter_entries_by_dir()
2255.2.88 by Robert Collins
Significant steps back to operation.
1147
        # we will be modifying the dirstate, so we need a stable iterator. In
1148
        # future we might write one, for now we just clone the state into a
1149
        # list - which is a shallow copy, so each 
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1150
        old_iterator = iter(list(self._iter_entries()))
1151
        # both must have roots so this is safe:
1152
        current_new = new_iterator.next()
1153
        current_old = old_iterator.next()
1154
        def advance(iterator):
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.
1155
            try:
2255.2.88 by Robert Collins
Significant steps back to operation.
1156
                return iterator.next()
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1157
            except StopIteration:
1158
                return None
1159
        while current_new or current_old:
1160
            # skip entries in old that are not really there
2255.2.88 by Robert Collins
Significant steps back to operation.
1161
            if current_old and current_old[1][0][0] in ('relocated', 'absent'):
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1162
                current_old = advance(old_iterator)
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.
1163
                continue
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1164
            if current_new:
1165
                # convert new into dirblock style
2255.2.88 by Robert Collins
Significant steps back to operation.
1166
                new_path_utf8 = current_new[0].encode('utf8')
1167
                new_dirname, new_basename = os.path.split(new_path_utf8)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1168
                new_id = current_new[1].file_id.encode('utf8')
1169
                new_entry_key = (new_dirname, new_basename, new_id)
2255.2.88 by Robert Collins
Significant steps back to operation.
1170
            else:
1171
                # for safety disable variables
1172
                new_path_utf8 = new_dirname = new_basename = new_id = new_entry_key = None
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1173
            # 5 cases, we dont have a value that is strictly greater than everything, so
1174
            # we make both end conditions explicit
1175
            if not current_old:
1176
                # old is finished: insert current_new into the state.
1177
                self.update_minimal(new_entry_key, current_new[1].kind,
2255.2.88 by Robert Collins
Significant steps back to operation.
1178
                    num_present_parents, executable=current_new[1].executable,
1179
                    id_index=id_index, path_utf8=new_path_utf8)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1180
                current_new = advance(new_iterator)
1181
            elif not current_new:
1182
                # new is finished
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1183
                self._make_absent(current_old, id_index)
2255.2.88 by Robert Collins
Significant steps back to operation.
1184
                current_old = advance(old_iterator)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1185
            elif new_entry_key == current_old[0]:
1186
                # same -  common case
1187
                # TODO: update the record if anything significant has changed.
2255.2.88 by Robert Collins
Significant steps back to operation.
1188
                # the minimal required trigger is if the execute bit or cached
1189
                # kind has changed.
1190
                if (current_old[1][0][3] != current_new[1].executable or
1191
                    current_old[1][0][0] != current_new[1].kind):
1192
                    self.update_minimal(current_old[0], current_new[1].kind,
1193
                        num_present_parents,
1194
                        executable=current_new[1].executable,
1195
                        id_index=id_index, path_utf8=new_path_utf8)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1196
                # both sides are dealt with, move on
1197
                current_old = advance(old_iterator)
1198
                current_new = advance(new_iterator)
1199
            elif new_entry_key < current_old[0]:
2255.2.88 by Robert Collins
Significant steps back to operation.
1200
                # new comes before:
1201
                # add a entry for this and advance new
1202
                self.update_minimal(new_entry_key, current_new[1].kind,
1203
                    num_present_parents, executable=current_new[1].executable,
1204
                    id_index=id_index, path_utf8=new_path_utf8)
1205
                current_new = advance(new_iterator)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1206
            else:
1207
                # old comes before:
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1208
                self._make_absent(current_old, id_index)
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1209
                current_old = advance(old_iterator)
1210
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1211
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1212
    def _make_absent(self, current_old, id_index=None):
1213
        """Mark current_old - an entry - as absent for tree 0.
1214
1215
        :param id_index: An index from fileid_utf8 to sets of keys, used by
1216
            some functions. If provided it will be updated if needed.
1217
        :return: True if this was the last details entry for they entry key:
1218
            that is, if the underlying block has had the entry removed, thus
1219
            shrinking in legnth.
1220
        """
1221
        # build up paths that this id will be left at after the change is made,
1222
        # so we can update their cross references in tree 0
1223
        all_remaining_keys = set()
1224
        # Dont check the working tree, because its going.
1225
        for details in current_old[1][1:]:
1226
            if details[0] not in ('absent', 'relocated'):
1227
                all_remaining_keys.add(current_old[0])
1228
            elif details[0] == 'relocated':
1229
                # record the key for the real path.
2255.2.99 by Robert Collins
Dirstate - fix _find_block to create missing blocks when the parent is versioned in the current tree, and fix handling of relocated entries in _make_absent.
1230
                all_remaining_keys.add(tuple(os.path.split(details[1])) + (current_old[0][2],))
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1231
            # absent rows are not present at any path.
1232
        last_reference = current_old[0] not in all_remaining_keys
1233
        if last_reference:
1234
            # the current row consists entire of the current item (being marked
1235
            # absent), and relocated or absent entries for the other trees:
1236
            # Remove it, its meaningless.
2255.2.88 by Robert Collins
Significant steps back to operation.
1237
            block = self._find_block(current_old[0])
1238
            entry_index, present = self._find_entry_index(current_old[0], block[1])
1239
            assert present
1240
            block[1].pop(entry_index)
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1241
            # if we have an id_index in use, remove this key from it for this id.
1242
            if id_index is not None:
1243
                id_index[current_old[0][2]].remove(current_old[0])
1244
        # update all remaining keys for this id to record it as absent. The
1245
        # existing details may either be the record we are making as deleted
1246
        # (if there were other trees with the id present at this path), or may
1247
        # be relocations.
1248
        for update_key in all_remaining_keys:
1249
            update_block_index, present = \
1250
                self._find_block_index_from_key(update_key)
1251
            assert present
1252
            update_entry_index, present = \
1253
                self._find_entry_index(update_key, self._dirblocks[update_block_index][1])
1254
            assert present
1255
            update_tree_details = self._dirblocks[update_block_index][1][update_entry_index][1]
1256
            # it must not be absent at the moment
1257
            assert update_tree_details[0][0] != 'absent'
1258
            update_tree_details[0] = DirState.NULL_PARENT_DETAILS
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1259
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
2255.2.93 by Robert Collins
Dirstate - update WorkingTree4.unversion to the new layout, other tests still borked.
1260
        return last_reference
2255.2.88 by Robert Collins
Significant steps back to operation.
1261
1262
    def update_minimal(self, key, kind, num_present_parents, executable=False,
1263
        fingerprint='', packed_stat=None, size=0, id_index=None,
1264
        path_utf8=None):
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1265
        """Update an entry to the state in tree 0."""
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1266
        block = self._find_block(key)[1]
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1267
        if packed_stat is None:
1268
            packed_stat = DirState.NULLSTAT
1269
        entry_index, present = self._find_entry_index(key, block)
1270
        new_details = (kind, fingerprint, size, executable, packed_stat)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1271
        assert id_index is not None, 'need an id index to do updates for now !'
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1272
        if not present:
1273
            # new entry, synthesis cross reference here,
2255.2.88 by Robert Collins
Significant steps back to operation.
1274
            existing_keys = id_index.setdefault(key[2], set())
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1275
            if not existing_keys:
1276
                # not currently in the state, simplest case
1277
                new_entry = key, [new_details] + self._empty_parent_info()
1278
            else:
2255.2.88 by Robert Collins
Significant steps back to operation.
1279
                # present at one or more existing other paths.
1280
                # grab one of them and use it to generate parent
1281
                # relocation/absent entries.
1282
                new_entry = key, [new_details]
1283
                for other_key in existing_keys:
1284
                    # change the record at other to be a pointer to this new
1285
                    # record. The loop looks similar to the change to
1286
                    # relocations when updating an existing record but its not:
1287
                    # the test for existing kinds is different: this can be
1288
                    # factored out to a helper though.
1289
                    other_block_index, present = self._find_block_index_from_key(other_key)
1290
                    assert present
1291
                    other_entry_index, present = self._find_entry_index(other_key, self._dirblocks[other_block_index][1])
1292
                    assert present
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1293
                    assert path_utf8 is not None
2255.2.88 by Robert Collins
Significant steps back to operation.
1294
                    self._dirblocks[other_block_index][1][other_entry_index][1][0] = \
1295
                        ('relocated', path_utf8, 0, False, '')
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1296
2255.2.88 by Robert Collins
Significant steps back to operation.
1297
                for lookup_index in xrange(1, num_present_parents + 1):
1298
                    # grab any one entry, use it to find the right path.
1299
                    # TODO: optimise this to reduce memory use in highly 
1300
                    # fragmented situations by reusing the relocation
1301
                    # records.
1302
                    update_block_index, present = \
1303
                        self._find_block_index_from_key(other_key)
1304
                    assert present
1305
                    update_entry_index, present = \
1306
                        self._find_entry_index(other_key, self._dirblocks[update_block_index][1])
1307
                    assert present
1308
                    update_details = self._dirblocks[update_block_index][1][update_entry_index][1][lookup_index]
1309
                    if update_details[0] in ('relocated', 'absent'):
1310
                        # its a pointer or absent in lookup_index's tree, use
1311
                        # it as is.
1312
                        new_entry[1].append(update_details)
1313
                    else:
1314
                        # we have the right key, make a pointer to it.
2255.2.89 by Robert Collins
Fix addition of relocation records when we encounter the correct location first try.
1315
                        pointer_path = os.path.join(*other_key[0:2])
1316
                        new_entry[1].append(('relocated', pointer_path, 0, False, ''))
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1317
            block.insert(entry_index, new_entry)
1318
            existing_keys.add(key)
1319
        else:
1320
            # Does the new state matter? 
1321
            block[entry_index][1][0] = new_details
2255.2.88 by Robert Collins
Significant steps back to operation.
1322
            # parents cannot be affected by what we do.
1323
            # other occurences of this id can be found 
1324
            # from the id index.
1325
            # ---
1326
            # tree index consistency: All other paths for this id in this tree
1327
            # index must point to the correct path. We have to loop here because
1328
            # we may have passed entries in the state with this file id already
1329
            # that were absent - where parent entries are - and they need to be
1330
            # converted to relocated.
1331
            assert path_utf8 is not None
1332
            for entry_key in id_index.setdefault(key[2], set()):
1333
                # TODO:PROFILING: It might be faster to just update
1334
                # rather than checking if we need to, and then overwrite
1335
                # the one we are located at.
1336
                if entry_key != key:
1337
                    # this file id is at a different path in one of the
1338
                    # other trees, so put absent pointers there
1339
                    # This is the vertical axis in the matrix, all pointing
1340
                    # to the real path.
1341
                    block_index, present = self._find_block_index_from_key(entry_key)
1342
                    assert present
1343
                    entry_index, present = self._find_entry_index(entry_key, self._dirblocks[block_index][1])
1344
                    assert present
1345
                    self._dirblocks[block_index][1][entry_index][1][0] = \
1346
                        ('relocated', path_utf8, 0, False, '')
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1347
        # add a containing dirblock if needed.
1348
        if new_details[0] == 'directory':
1349
            subdir_key = (os.path.join(*key[0:2]), '', '')
1350
            block_index, present = self._find_block_index_from_key(subdir_key)
1351
            if not present:
1352
                self._dirblocks.insert(block_index, (subdir_key[0], []))
2255.2.88 by Robert Collins
Significant steps back to operation.
1353
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1354
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1355
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.
1356
1852.13.20 by Robert Collins
Steps toward an object model.
1357
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
1358
def pack_stat(st, _encode=base64.encodestring, _pack=struct.pack):
1359
    """Convert stat values into a packed representation."""
1360
    # jam 20060614 it isn't really worth removing more entries if we
1361
    # are going to leave it in packed form.
1362
    # With only st_mtime and st_mode filesize is 5.5M and read time is 275ms
1363
    # With all entries filesize is 5.9M and read time is mabye 280ms
1364
    # well within the noise margin
1365
1366
    # base64.encode always adds a final newline, so strip it off
1367
    return _encode(_pack('>llllll'
1368
        , st.st_size, st.st_mtime, st.st_ctime
1369
        , st.st_dev, st.st_ino, st.st_mode))[:-1]
1370