3
# Copyright (C) 2005 Canonical Ltd
7
# Author: Martin Pool <mbp@canonical.com>
10
"""knit - a weave-like structure
12
A Knit manages versions of line-based text files, keeping track of the
13
originating version for each line.
15
Versions are referenced by nonnegative integers. In a full system
16
this will be just a local shorthand for some universally-unique
19
Texts are represented as a seqence of (version, text, live) tuples.
20
An empty sequence represents an empty text. The version is the
21
version in which the line was introduced. The *live* flag is false if
22
the line is no longer present and being tracked only for the purposes
27
text1 = [(0, "hello world", True)]
29
knit2 = [(0, "hello world", True),
30
(1, "hello boys", True)
35
def show_annotated(knit):
36
"""Show a knit in 'blame' style"""
37
for vers, text, live in knit:
40
print '%6d | %s' % (vers, text)
44
"""Return a sequence of lines containing just the live text from a knit."""
45
return [text for (vers, text, live) in knit if live]
49
def update_knit(knit, new_vers, new_lines):
50
"""Return a new knit whose text matches new_lines.
52
First of all the knit is diffed against the new lines, considering
53
only the text of the lines from the knit. This identifies lines
54
unchanged from the knit, plus insertions and deletions.
56
The deletions are marked as deleted. The insertions are added
57
with their new values.
61
if not isinstance(new_vers, int):
62
raise TypeError('new version-id must be an int: %r' % new_vers)
64
from difflib import SequenceMatcher
65
knit_lines = knit2text(knit)
66
m = SequenceMatcher(None, knit_lines, new_lines)
68
for block in m.get_matching_blocks():
69
print "a[%d] and b[%d] match for %d elements" % block
72
for tag, i1, i2, j1, j2 in m.get_opcodes():
73
print ("%7s a[%d:%d] (%s) b[%d:%d] (%s)" %
74
(tag, i1, i2, knit_lines[i1:i2], j1, j2, new_lines[j1:j2]))
77
new_knit.extend(knit[i1:i2])
79
for i in range(i1, i2):
81
new_knit.append((kl[0], kl[1], False))
88
print '***** annotated:'
91
print '***** plain text:'
92
print '\n'.join(knit2text(knit2))
94
text3 = """hello world
96
hello boys""".split('\n')
98
print repr(knit2text(knit2))
100
knit3 = update_knit(knit2, 3, text3)
102
print '***** result of update:'
103
show_annotated(knit3)