~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to knit.py

  • Committer: Martin Pool
  • Date: 2005-06-27 02:18:05 UTC
  • mto: This revision was merged to the branch mainline in revision 852.
  • Revision ID: mbp@sourcefrog.net-20050627021805-13222ad1af28eeae
Check in old existing knit code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/python
 
2
 
 
3
# Copyright (C) 2005 Canonical Ltd
 
4
 
 
5
# GNU GPL v2
 
6
 
 
7
# Author: Martin Pool <mbp@canonical.com>
 
8
 
 
9
 
 
10
"""knit - a weave-like structure
 
11
 
 
12
A Knit manages versions of line-based text files, keeping track of the
 
13
originating version for each line.
 
14
 
 
15
Versions are referenced by nonnegative integers.  In a full system
 
16
this will be just a local shorthand for some universally-unique
 
17
version identifier.
 
18
 
 
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
 
23
of merging.
 
24
"""
 
25
 
 
26
 
 
27
text1 = [(0, "hello world", True)]
 
28
 
 
29
knit2 = [(0, "hello world", True),
 
30
         (1, "hello boys", True)
 
31
         ]
 
32
 
 
33
 
 
34
 
 
35
def show_annotated(knit):
 
36
    """Show a knit in 'blame' style"""
 
37
    for vers, text, live in knit:
 
38
        if not live:
 
39
            continue
 
40
        print '%6d | %s' % (vers, text)
 
41
 
 
42
 
 
43
def knit2text(knit):
 
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]
 
46
 
 
47
 
 
48
 
 
49
def update_knit(knit, new_vers, new_lines):
 
50
    """Return a new knit whose text matches new_lines.
 
51
 
 
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.
 
55
 
 
56
    The deletions are marked as deleted.  The insertions are added
 
57
    with their new values.
 
58
 
 
59
    
 
60
    """
 
61
    if not isinstance(new_vers, int):
 
62
        raise TypeError('new version-id must be an int: %r' % new_vers)
 
63
    
 
64
    from difflib import SequenceMatcher
 
65
    knit_lines = knit2text(knit)
 
66
    m = SequenceMatcher(None, knit_lines, new_lines)
 
67
 
 
68
    for block in m.get_matching_blocks():
 
69
        print "a[%d] and b[%d] match for %d elements" % block
 
70
    
 
71
    new_knit = []
 
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]))
 
75
 
 
76
        if tag == 'equal':
 
77
            new_knit.extend(knit[i1:i2])
 
78
        elif tag == 'delete':
 
79
            for i in range(i1, i2):
 
80
                kl = knit[i]
 
81
                new_knit.append((kl[0], kl[1], False))
 
82
 
 
83
    return new_knit
 
84
        
 
85
    
 
86
 
 
87
 
 
88
print '***** annotated:'
 
89
show_annotated(knit2)
 
90
 
 
91
print '***** plain text:'
 
92
print '\n'.join(knit2text(knit2))
 
93
 
 
94
text3 = """hello world
 
95
an inserted line
 
96
hello boys""".split('\n')
 
97
 
 
98
print repr(knit2text(knit2))
 
99
print repr(text3)
 
100
knit3 = update_knit(knit2, 3, text3)
 
101
 
 
102
print '***** result of update:'
 
103
show_annotated(knit3)
 
104
 
 
105
 
 
106