~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to knit.py

  • Committer: Martin Pool
  • Date: 2005-06-27 03:19:33 UTC
  • mto: This revision was merged to the branch mainline in revision 852.
  • Revision ID: mbp@sourcefrog.net-20050627031933-8c7311c41a7148d3
Add stubbed-out TestSkipped

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
 
 
13
class Knit(object):
 
14
    """knit - versioned text file storage.
 
15
    
 
16
    A Knit manages versions of line-based text files, keeping track of the
 
17
    originating version for each line.
 
18
 
 
19
    Texts can be identified in either of two ways:
 
20
 
 
21
    * a nonnegative index number.
 
22
 
 
23
    * a version-id string.
 
24
 
 
25
    Typically the index number will be valid only inside this knit and
 
26
    the version-id is used to reference it in the larger world.
 
27
 
 
28
    _l
 
29
        List of edit instructions.
 
30
 
 
31
        Each line is stored as a tuple of (index-id, text).  The line
 
32
        is present in the version equal to index-id.
 
33
 
 
34
    _v
 
35
        List of versions, indexed by index number.  Each one is an empty
 
36
        tuple because the version_id isn't stored yet.
 
37
    """
 
38
    def __init__(self):
 
39
        self._l = []
 
40
        self._v = []
 
41
 
 
42
        
 
43
    def add(self, text):
 
44
        """Add a single text on top of the weave.
 
45
 
 
46
        Returns the index number of the newly added version."""
 
47
        if not isinstance(text, list):
 
48
            raise ValueError("text should be a list, not %s" % type(text))
 
49
 
 
50
        idx = len(self._v)
 
51
 
 
52
        # all of the previous texts are turned off; just append lines at the bottom
 
53
        for line in text:
 
54
            self._l.append((idx, line))
 
55
 
 
56
        self._v.append(())
 
57
        return idx
 
58
 
 
59
    
 
60
    def annotate(self, index):
 
61
        return list(self.annotate_iter(index))
 
62
 
 
63
 
 
64
    def annotate_iter(self, index):
 
65
        """Yield list of (index-id, line) pairs for the specified version.
 
66
 
 
67
        The index indicates when the line originated in the weave."""
 
68
        self._v[index]                  # check index is valid
 
69
 
 
70
        for origin, line in self._l:
 
71
            if origin == index:
 
72
                yield origin, line
 
73
 
 
74
 
 
75
    def getiter(self, index):
 
76
        """Yield lines for the specified version."""
 
77
        for origin, line in self.annotate_iter(index):
 
78
            yield line
 
79
 
 
80
 
 
81
    def get(self, index):
 
82
        return list(self.getiter(index))
 
83
 
 
84
 
 
85
    def dump(self, to_file):
 
86
        from pprint import pprint
 
87
        print >>to_file, "knit lines:"
 
88
        pprint(self._l, to_file)
 
89
 
 
90
 
 
91
 
 
92
def update_knit(knit, new_vers, new_lines):
 
93
    """Return a new knit whose text matches new_lines.
 
94
 
 
95
    First of all the knit is diffed against the new lines, considering
 
96
    only the text of the lines from the knit.  This identifies lines
 
97
    unchanged from the knit, plus insertions and deletions.
 
98
 
 
99
    The deletions are marked as deleted.  The insertions are added
 
100
    with their new values.
 
101
 
 
102
    
 
103
    """
 
104
    if not isinstance(new_vers, int):
 
105
        raise TypeError('new version-id must be an int: %r' % new_vers)
 
106
    
 
107
    from difflib import SequenceMatcher
 
108
    knit_lines = knit2text(knit)
 
109
    m = SequenceMatcher(None, knit_lines, new_lines)
 
110
 
 
111
    for block in m.get_matching_blocks():
 
112
        print "a[%d] and b[%d] match for %d elements" % block
 
113
    
 
114
    new_knit = []
 
115
    for tag, i1, i2, j1, j2 in m.get_opcodes():
 
116
        print ("%7s a[%d:%d] (%s) b[%d:%d] (%s)" %
 
117
               (tag, i1, i2, knit_lines[i1:i2], j1, j2, new_lines[j1:j2]))
 
118
 
 
119
        if tag == 'equal':
 
120
            new_knit.extend(knit[i1:i2])
 
121
        elif tag == 'delete':
 
122
            for i in range(i1, i2):
 
123
                kl = knit[i]
 
124
                new_knit.append((kl[0], kl[1], False))
 
125
 
 
126
    return new_knit
 
127
        
 
128