~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: Martin Pool
  • Date: 2005-07-18 11:37:33 UTC
  • Revision ID: mbp@sourcefrog.net-20050718113733-39beb81b0e1ead4d
- don't intern weave text; it doesn't seem to help

Show diffs side-by-side

added added

removed removed

Lines of Context:
71
71
# properly nested, that there is no text outside of an insertion, that
72
72
# insertions or deletions are not repeated, etc.
73
73
 
 
74
# TODO: Make the info command just show info, not extract everything:
 
75
# it can be much faster.
 
76
 
 
77
# TODO: Perhaps use long integers as sets instead of set objects; may
 
78
# be faster.
 
79
 
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.
108
114
 
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.
113
119
 
151
157
      should be no way to get an earlier version deleting a later
152
158
      version.
153
159
 
154
 
    _weave
155
 
        Text of the weave; list of control instruction tuples and strings.
 
160
    _l
 
161
        Text of the weave.
156
162
 
157
 
    _parents
 
163
    _v
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.
164
170
    """
165
171
 
166
 
    __slots__ = ['_weave', '_parents', '_sha1s']
 
172
    ## __slots__ = ['_l', '_v', '_sha1s']
167
173
    
168
174
    def __init__(self):
169
 
        self._weave = []
170
 
        self._parents = []
 
175
        self._l = []
 
176
        self._v = []
171
177
        self._sha1s = []
172
178
 
173
179
 
174
180
    def __eq__(self, other):
175
181
        if not isinstance(other, Weave):
176
182
            return False
177
 
        return self._parents == other._parents \
178
 
               and self._weave == other._weave
 
183
        return self._v == other._v \
 
184
               and self._l == other._l
179
185
    
180
186
 
181
187
    def __ne__(self, other):
195
201
 
196
202
        self._check_versions(parents)
197
203
        ## self._check_lines(text)
198
 
        new_version = len(self._parents)
 
204
        new_version = len(self._v)
199
205
 
200
206
        import sha
201
207
        s = sha.new()
204
210
        del s
205
211
 
206
212
        # if we abort after here the weave will be corrupt
207
 
        self._parents.append(frozenset(parents))
 
213
        self._v.append(frozenset(parents))
208
214
        self._sha1s.append(sha1)
209
215
 
210
216
            
214
220
            # even more specially, if we're adding an empty text we
215
221
            # need do nothing at all.
216
222
            if text:
217
 
                self._weave.append(('{', new_version))
218
 
                self._weave.extend(text)
219
 
                self._weave.append(('}', new_version))
 
223
                self._l.append(('{', new_version))
 
224
                self._l.extend(text)
 
225
                self._l.append(('}', new_version))
220
226
        
221
227
            return new_version
222
228
 
223
 
        if len(parents) == 1:
224
 
            pv = list(parents)[0]
225
 
            if sha1 == self._sha1s[pv]:
226
 
                # special case: same as the single parent
227
 
                return new_version
 
229
        if len(parents) == 1 and sha1 == self._sha1s[parents[0]]:
 
230
            # special case: same as the single parent
 
231
            return new_version
228
232
            
229
233
 
230
234
        ancestors = self.inclusions(parents)
231
235
 
232
 
        l = self._weave
 
236
        l = self._l
233
237
 
234
238
        # basis a list of (origin, lineno, line)
235
239
        basis_lineno = []
243
247
            return new_version            
244
248
 
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))
247
251
 
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]
272
276
 
 
277
            assert 0 <= i1 <= i2 <= len(old_l)
273
278
            assert 0 <= j1 <= j2 <= len(text)
274
279
 
275
280
            #print tag, i1, i2, j1, j2
277
282
            # the deletion and insertion are handled separately.
278
283
            # first delete the region.
279
284
            if i1 != i2:
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))
282
287
                offset += 2
283
288
 
284
289
            if j1 != j2:
286
291
                # i2; we want to insert after this region to make sure
287
292
                # we don't destroy ourselves
288
293
                i = i2 + offset
289
 
                self._weave[i:i] = ([('{', new_version)] 
 
294
                self._l[i:i] = ([('{', new_version)] 
290
295
                                + text[j1:j2] 
291
296
                                + [('}', new_version)])
292
297
                offset += 2 + (j2 - j1)
302
307
            while v >= 0:
303
308
                if v in i:
304
309
                    # include all its parents
305
 
                    i.update(self._parents[v])
 
310
                    i.update(self._v[v])
306
311
                v -= 1
307
312
            return i
308
313
        except IndexError:
311
316
 
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]
315
320
        if not included:
316
321
            return []
317
322
        
347
352
        """Check everything in the sequence of indexes is valid"""
348
353
        for i in indexes:
349
354
            try:
350
 
                self._parents[i]
 
355
                self._v[i]
351
356
            except IndexError:
352
357
                raise IndexError("invalid version number %r" % i)
353
358
 
377
382
 
378
383
        lineno = 0         # line of weave, 0-based
379
384
 
380
 
        for l in self._weave:
 
385
        for l in self._l:
381
386
            if isinstance(l, tuple):
382
387
                c, v = l
383
388
                isactive = None
423
428
 
424
429
        WFE = WeaveFormatError
425
430
 
426
 
        for l in self._weave:
 
431
        for l in self._l:
427
432
            if isinstance(l, tuple):
428
433
                c, v = l
429
434
                isactive = None
479
484
 
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)
486
491
 
487
492
 
488
493
 
489
494
    def numversions(self):
490
 
        l = len(self._parents)
 
495
        l = len(self._v)
491
496
        assert l == len(self._sha1s)
492
497
        return l
493
498
 
494
499
 
495
 
    def __len__(self):
496
 
        return self.numversions()
497
 
 
498
 
 
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])
503
504
            if inclusions:
504
505
                inclusions.sort()
505
506
                if inclusions[-1] >= version:
670
671
 
671
672
 
672
673
 
673
 
def weave_info(w):
 
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):
677
 
        print '-' * i,
678
 
    print
679
 
    for i in range(w.numversions()):
680
 
        sha1 = w._sha1s[i]
681
 
        print '%6d %40s %s' % (i, sha1, ' '.join(map(str, w._parents[i])))
682
 
 
683
 
 
684
 
 
685
 
def weave_stats(weave_file):
686
 
    from bzrlib.progress import ProgressBar
687
 
    from bzrlib.weavefile import read_weave
688
 
 
689
 
    pb = ProgressBar()
690
 
 
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)
695
683
 
696
684
    total = 0
697
 
    vers = len(w)
698
 
    for i in range(vers):
699
 
        pb.update('checking sizes', i, vers)
700
 
        for line in w.get_iter(i):
701
 
            total += len(line)
702
 
 
703
 
    pb.clear()
704
 
 
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))
709
 
 
 
685
    print '%6s %6s %8s %40s %20s' % ('ver', 'lines', 'bytes', 'sha1', 'parents')
 
686
    for i in (6, 6, 8, 40, 20):
 
687
        print '-' * i,
 
688
    print
 
689
    for i in range(len(w._v)):
 
690
        text = w.get(i)
 
691
        lines = len(text)
 
692
        bytes = sum((len(a) for a in text))
 
693
        sha1 = w._sha1s[i]
 
694
        print '%6d %6d %8d %40s' % (i, lines, bytes, sha1),
 
695
        for pv in w._v[i]:
 
696
            print pv,
 
697
        print
 
698
        total += bytes
 
699
 
 
700
    print >>out, "versions total %d bytes" % total
 
701
    print >>out, "compression ratio %.3f" % (float(total)/float(weave_size))
710
702
 
711
703
 
712
704
def usage():
810
802
                lasto = origin
811
803
                
812
804
    elif cmd == 'info':
813
 
        weave_info(readit())
814
 
 
815
 
    elif cmd == 'stats':
816
 
        weave_stats(argv[2])
 
805
        weave_info(argv[2], sys.stdout)
817
806
        
818
807
    elif cmd == 'check':
819
808
        w = readit()
828
817
 
829
818
    elif cmd == 'parents':
830
819
        w = readit()
831
 
        print ' '.join(map(str, w._parents[int(argv[3])]))
 
820
        print ' '.join(map(str, w._v[int(argv[3])]))
832
821
 
833
822
    elif cmd == 'plan-merge':
834
823
        w = readit()