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 |