71
71
# properly nested, that there is no text outside of an insertion, that
72
72
# insertions or deletions are not repeated, etc.
74
# TODO: Make the info command just show info, not extract everything:
75
# it can be much faster.
77
# TODO: Perhaps use long integers as sets instead of set objects; may
74
80
# TODO: Parallel-extract that passes back each line along with a
75
81
# description of which revisions include it. Nice for checking all
76
82
# shas in parallel.
107
113
the version-id is used to reference it in the larger world.
109
115
The weave is represented as a list mixing edit instructions and
110
literal text. Each entry in _weave can be either a string (or
116
literal text. Each entry in _l can be either a string (or
111
117
unicode), or a tuple. If a string, it means that the given line
112
118
should be output in the currently active revisions.
151
157
should be no way to get an earlier version deleting a later
155
Text of the weave; list of control instruction tuples and strings.
158
164
List of parents, indexed by version number.
159
165
It is only necessary to store the minimal set of parents for
160
166
each version; the parent's parents are implied.
163
169
List of hex SHA-1 of each version, or None if not recorded.
166
__slots__ = ['_weave', '_parents', '_sha1s']
172
## __slots__ = ['_l', '_v', '_sha1s']
168
174
def __init__(self):
174
180
def __eq__(self, other):
175
181
if not isinstance(other, Weave):
177
return self._parents == other._parents \
178
and self._weave == other._weave
183
return self._v == other._v \
184
and self._l == other._l
181
187
def __ne__(self, other):
214
220
# even more specially, if we're adding an empty text we
215
221
# need do nothing at all.
217
self._weave.append(('{', new_version))
218
self._weave.extend(text)
219
self._weave.append(('}', new_version))
223
self._l.append(('{', new_version))
225
self._l.append(('}', new_version))
221
227
return new_version
223
if len(parents) == 1:
224
pv = list(parents)[0]
225
if sha1 == self._sha1s[pv]:
226
# special case: same as the single parent
229
if len(parents) == 1 and sha1 == self._sha1s[parents[0]]:
230
# special case: same as the single parent
230
234
ancestors = self.inclusions(parents)
234
238
# basis a list of (origin, lineno, line)
235
239
basis_lineno = []
243
247
return new_version
245
249
# add a sentinal, because we can also match against the final line
246
basis_lineno.append(len(self._weave))
250
basis_lineno.append(len(self._l))
248
252
# XXX: which line of the weave should we really consider
249
253
# matches the end of the file? the current code says it's the
270
274
i1 = basis_lineno[i1]
271
275
i2 = basis_lineno[i2]
277
assert 0 <= i1 <= i2 <= len(old_l)
273
278
assert 0 <= j1 <= j2 <= len(text)
275
280
#print tag, i1, i2, j1, j2
277
282
# the deletion and insertion are handled separately.
278
283
# first delete the region.
280
self._weave.insert(i1+offset, ('[', new_version))
281
self._weave.insert(i2+offset+1, (']', new_version))
285
self._l.insert(i1+offset, ('[', new_version))
286
self._l.insert(i2+offset+1, (']', new_version))
286
291
# i2; we want to insert after this region to make sure
287
292
# we don't destroy ourselves
289
self._weave[i:i] = ([('{', new_version)]
294
self._l[i:i] = ([('{', new_version)]
291
296
+ [('}', new_version)])
292
297
offset += 2 + (j2 - j1)
312
317
def minimal_parents(self, version):
313
318
"""Find the minimal set of parents for the version."""
314
included = self._parents[version]
319
included = self._v[version]
480
485
def dump(self, to_file):
481
486
from pprint import pprint
482
print >>to_file, "Weave._weave = ",
483
pprint(self._weave, to_file)
484
print >>to_file, "Weave._parents = ",
485
pprint(self._parents, to_file)
487
print >>to_file, "Weave._l = ",
488
pprint(self._l, to_file)
489
print >>to_file, "Weave._v = ",
490
pprint(self._v, to_file)
489
494
def numversions(self):
490
l = len(self._parents)
491
496
assert l == len(self._sha1s)
496
return self.numversions()
499
500
def check(self, progress_bar=None):
500
501
# check no circular inclusions
501
502
for version in range(self.numversions()):
502
inclusions = list(self._parents[version])
503
inclusions = list(self._v[version])
504
505
inclusions.sort()
505
506
if inclusions[-1] >= version:
674
def weave_info(filename, out):
674
675
"""Show some text information about the weave."""
675
print '%6s %40s %20s' % ('ver', 'sha1', 'parents')
676
for i in (6, 40, 20):
679
for i in range(w.numversions()):
681
print '%6d %40s %s' % (i, sha1, ' '.join(map(str, w._parents[i])))
685
def weave_stats(weave_file):
686
from bzrlib.progress import ProgressBar
687
from bzrlib.weavefile import read_weave
691
wf = file(weave_file, 'rb')
676
from weavefile import read_weave
677
wf = file(filename, 'rb')
692
678
w = read_weave(wf)
693
679
# FIXME: doesn't work on pipes
694
680
weave_size = wf.tell()
681
print >>out, "weave file size %d bytes" % weave_size
682
print >>out, "weave contains %d versions" % len(w._v)
698
for i in range(vers):
699
pb.update('checking sizes', i, vers)
700
for line in w.get_iter(i):
705
print 'versions %9d' % vers
706
print 'weave file %9d bytes' % weave_size
707
print 'total contents %9d bytes' % total
708
print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
685
print '%6s %6s %8s %40s %20s' % ('ver', 'lines', 'bytes', 'sha1', 'parents')
686
for i in (6, 6, 8, 40, 20):
689
for i in range(len(w._v)):
692
bytes = sum((len(a) for a in text))
694
print '%6d %6d %8d %40s' % (i, lines, bytes, sha1),
700
print >>out, "versions total %d bytes" % total
701
print >>out, "compression ratio %.3f" % (float(total)/float(weave_size))