~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: Robert Collins
  • Date: 2006-03-14 10:27:28 UTC
  • mto: (1615.1.2 bzr.mbp.integration)
  • mto: This revision was merged to the branch mainline in revision 1616.
  • Revision ID: robertc@robertcollins.net-20060314102728-7e47b9b8cd6c3d73
rollback from using deltas to using fulltexts - deltas need more work to be ready.

Show diffs side-by-side

added added

removed removed

Lines of Context:
262
262
 
263
263
    def get_delta(self, version_id):
264
264
        """See VersionedFile.get_delta."""
265
 
        if not self.has_version(version_id):
266
 
            raise RevisionNotPresent(version_id, self)
267
 
        sha1 = self.get_sha1(version_id)
268
 
        parents = self.get_parents(version_id)
269
 
        if len(parents):
270
 
            parent = parents[0]
271
 
            parent_inclusions = set(self.get_ancestry(parent))
272
 
        else:
273
 
            parent = None
274
 
            parent_inclusions = set()
275
 
        # we want to emit start, finish, replacement_length, replacement_lines tuples.
276
 
        diff_hunks = []
277
 
        current_hunk = [0, 0, 0, []] #start, finish, repl_length, repl_tuples
278
 
        inclusions = set(self.get_ancestry(version_id))
279
 
        parent_linenum = 0
280
 
        noeol = False
281
 
        parent_noeol = False
282
 
        last_parent_line = ''
283
 
        for lineno, inserted, deletes, line in self._walk_internal(inclusions):
284
 
            parent_active = inserted in parent_inclusions and not (deletes & parent_inclusions)
285
 
            version_active = inserted in inclusions and not (deletes & inclusions)
286
 
            if not parent_active and not version_active:
287
 
                # unrelated line of ancestry
288
 
                pass
289
 
            elif parent_active and version_active:
290
 
                # shared line
291
 
                if current_hunk != [parent_linenum, parent_linenum, 0, []]:
292
 
                    diff_hunks.append(tuple(current_hunk))
293
 
                parent_linenum += 1
294
 
                current_hunk = [parent_linenum, parent_linenum, 0, []]
295
 
                if len(line) and line[-1] != '\n':
296
 
                    noeol = True
297
 
            elif parent_active and not version_active:
298
 
                # deleted line
299
 
                current_hunk[1] += 1
300
 
                parent_linenum += 1
301
 
                last_parent_line = line
302
 
            elif not parent_active and version_active:
303
 
                # replacement line
304
 
                # noeol only occurs at the end of a file because we 
305
 
                # diff linewise. We want to show noeol changes as a
306
 
                # empty diff unless the actual eol-less content changed.
307
 
                if len(last_parent_line) and last_parent_line[-1] != '\n':
308
 
                    parent_noeol = True
309
 
                if len(line) and line[-1] != '\n':
310
 
                    noeol = True
311
 
                changed = False
312
 
                if parent_noeol == noeol:
313
 
                    # no noeol toggle, so trust the weave
314
 
                    changed = True
315
 
                elif parent_noeol:
316
 
                    # parent is shorter:
317
 
                    if last_parent_line != line[:-1]:
318
 
                        # but changed anyway
319
 
                        changed = True
320
 
                elif noeol:
321
 
                    # append a eol so that it looks like
322
 
                    # a normalised delta
323
 
                    line = line + '\n'
324
 
                    # we are shorter:
325
 
                    if last_parent_line != line:
326
 
                        # but changed anyway
327
 
                        changed = True
328
 
                if changed:
329
 
                    current_hunk[2] += 1
330
 
                    current_hunk[3].append((inserted, line))
331
 
                else:
332
 
                    # last hunk last parent line is not eaten
333
 
                    current_hunk[1] -= 1
 
265
        return self.get_deltas([version_id])[version_id]
 
266
 
 
267
    def get_deltas(self, version_ids):
 
268
        """See VersionedFile.get_deltas."""
 
269
        version_ids = self.get_ancestry(version_ids)
 
270
        for version_id in version_ids:
 
271
            if not self.has_version(version_id):
 
272
                raise RevisionNotPresent(version_id, self)
 
273
        # try extracting all versions; parallel extraction is used
 
274
        nv = self.num_versions()
 
275
        sha1s = {}
 
276
        deltas = {}
 
277
        texts = {}
 
278
        inclusions = {}
 
279
        noeols = {}
 
280
        last_parent_lines = {}
 
281
        parents = {}
 
282
        parent_inclusions = {}
 
283
        parent_linenums = {}
 
284
        parent_noeols = {}
 
285
        current_hunks = {}
 
286
        diff_hunks = {}
 
287
        # its simplest to generate a full set of prepared variables.
 
288
        for i in range(nv):
 
289
            name = self._names[i]
 
290
            sha1s[name] = self.get_sha1(name)
 
291
            parents_list = self.get_parents(name)
 
292
            try:
 
293
                parent = parents_list[0]
 
294
                parents[name] = parent
 
295
                parent_inclusions[name] = inclusions[parent]
 
296
            except IndexError:
 
297
                parents[name] = None
 
298
                parent_inclusions[name] = set()
 
299
            # we want to emit start, finish, replacement_length, replacement_lines tuples.
 
300
            diff_hunks[name] = []
 
301
            current_hunks[name] = [0, 0, 0, []] # #start, finish, repl_length, repl_tuples
 
302
            parent_linenums[name] = 0
 
303
            noeols[name] = False
 
304
            parent_noeols[name] = False
 
305
            last_parent_lines[name] = None
 
306
            new_inc = set([name])
 
307
            for p in self._parents[i]:
 
308
                new_inc.update(inclusions[self._idx_to_name(p)])
 
309
            # debug only, known good so far.
 
310
            #assert set(new_inc) == set(self.get_ancestry(name)), \
 
311
            #    'failed %s != %s' % (set(new_inc), set(self.get_ancestry(name)))
 
312
            inclusions[name] = new_inc
 
313
 
 
314
        nlines = len(self._weave)
 
315
 
 
316
        for lineno, inserted, deletes, line in self._walk_internal():
 
317
            # a line is active in a version if:
 
318
            # insert is in the versions inclusions
 
319
            # and
 
320
            # deleteset & the versions inclusions is an empty set.
 
321
            # so - if we have a included by mapping - version is included by
 
322
            # children, we get a list of children to examine for deletes affect
 
323
            # ing them, which is less than the entire set of children.
 
324
            for version_id in version_ids:  
 
325
                # The active inclusion must be an ancestor,
 
326
                # and no ancestors must have deleted this line,
 
327
                # because we don't support resurrection.
 
328
                parent_inclusion = parent_inclusions[version_id]
 
329
                inclusion = inclusions[version_id]
 
330
                parent_active = inserted in parent_inclusion and not (deletes & parent_inclusion)
 
331
                version_active = inserted in inclusion and not (deletes & inclusion)
 
332
                if not parent_active and not version_active:
 
333
                    # unrelated line of ancestry
 
334
                    continue
 
335
                elif parent_active and version_active:
 
336
                    # shared line
 
337
                    parent_linenum = parent_linenums[version_id]
 
338
                    if current_hunks[version_id] != [parent_linenum, parent_linenum, 0, []]:
 
339
                        diff_hunks[version_id].append(tuple(current_hunks[version_id]))
 
340
                    parent_linenum += 1
 
341
                    current_hunks[version_id] = [parent_linenum, parent_linenum, 0, []]
 
342
                    parent_linenums[version_id] = parent_linenum
 
343
                    try:
 
344
                        if line[-1] != '\n':
 
345
                            noeols[version_id] = True
 
346
                    except IndexError:
 
347
                        pass
 
348
                elif parent_active and not version_active:
 
349
                    # deleted line
 
350
                    current_hunks[version_id][1] += 1
 
351
                    parent_linenums[version_id] += 1
 
352
                    last_parent_lines[version_id] = line
 
353
                elif not parent_active and version_active:
 
354
                    # replacement line
 
355
                    # noeol only occurs at the end of a file because we 
 
356
                    # diff linewise. We want to show noeol changes as a
 
357
                    # empty diff unless the actual eol-less content changed.
 
358
                    theline = line
 
359
                    try:
 
360
                        if last_parent_lines[version_id][-1] != '\n':
 
361
                            parent_noeols[version_id] = True
 
362
                    except (TypeError, IndexError):
 
363
                        pass
 
364
                    try:
 
365
                        if theline[-1] != '\n':
 
366
                            noeols[version_id] = True
 
367
                    except IndexError:
 
368
                        pass
 
369
                    new_line = False
 
370
                    parent_should_go = False
 
371
 
 
372
                    if parent_noeols[version_id] == noeols[version_id]:
 
373
                        # no noeol toggle, so trust the weaves statement
 
374
                        # that this line is changed.
 
375
                        new_line = True
 
376
                        if parent_noeols[version_id]:
 
377
                            theline = theline + '\n'
 
378
                    elif parent_noeols[version_id]:
 
379
                        # parent has no eol, we do:
 
380
                        # our line is new, report as such..
 
381
                        new_line = True
 
382
                    elif noeols[version_id]:
 
383
                        # append a eol so that it looks like
 
384
                        # a normalised delta
 
385
                        theline = theline + '\n'
 
386
                        if parents[version_id] is not None:
 
387
                        #if last_parent_lines[version_id] is not None:
 
388
                            parent_should_go = True
 
389
                        if last_parent_lines[version_id] != theline:
 
390
                            # but changed anyway
 
391
                            new_line = True
 
392
                            #parent_should_go = False
 
393
                    if new_line:
 
394
                        current_hunks[version_id][2] += 1
 
395
                        current_hunks[version_id][3].append((inserted, theline))
 
396
                    if parent_should_go:
 
397
                        # last hunk last parent line is not eaten
 
398
                        current_hunks[version_id][1] -= 1
 
399
                    if current_hunks[version_id][1] < 0:
 
400
                        current_hunks[version_id][1] = 0
 
401
                        # import pdb;pdb.set_trace()
 
402
                    # assert current_hunks[version_id][1] >= 0
 
403
 
334
404
        # flush last hunk
335
 
        if current_hunk != [0, 0, 0, []]:
336
 
            diff_hunks.append(tuple(current_hunk))
337
 
        return parent, sha1, noeol, diff_hunks
338
 
    
 
405
        for i in range(nv):
 
406
            version = self._idx_to_name(i)
 
407
            if current_hunks[version] != [0, 0, 0, []]:
 
408
                diff_hunks[version].append(tuple(current_hunks[version]))
 
409
        result = {}
 
410
        for version_id in version_ids:
 
411
            result[version_id] = (
 
412
                                  parents[version_id],
 
413
                                  sha1s[version_id],
 
414
                                  noeols[version_id],
 
415
                                  diff_hunks[version_id],
 
416
                                  )
 
417
        return result
 
418
 
339
419
    def get_parents(self, version_id):
340
420
        """See VersionedFile.get_parent."""
341
421
        return map(self._idx_to_name, self._parents[self._lookup(version_id)])
602
682
        lineno = 0         # line of weave, 0-based
603
683
 
604
684
        for l in self._weave:
605
 
            if isinstance(l, tuple):
 
685
            if l.__class__ == tuple:
606
686
                c, v = l
607
687
                isactive = None
608
688
                if c == '{':
609
 
                    istack.append(self._idx_to_name(v))
 
689
                    istack.append(self._names[v])
610
690
                elif c == '}':
611
691
                    istack.pop()
612
692
                elif c == '[':
613
 
                    assert self._idx_to_name(v) not in dset
614
 
                    dset.add(self._idx_to_name(v))
 
693
                    assert self._names[v] not in dset
 
694
                    dset.add(self._names[v])
615
695
                elif c == ']':
616
 
                    dset.remove(self._idx_to_name(v))
 
696
                    dset.remove(self._names[v])
617
697
                else:
618
698
                    raise WeaveFormatError('unexpected instruction %r' % v)
619
699
            else:
620
 
                assert isinstance(l, basestring)
 
700
                assert l.__class__ in (str, unicode)
621
701
                assert istack
622
 
                yield lineno, istack[-1], dset.copy(), l
 
702
                yield lineno, istack[-1], frozenset(dset), l
623
703
            lineno += 1
624
704
 
625
705
        if istack: