~bzr-pqm/bzr/bzr.dev

0.1.1 by Martin Pool
Check in old existing knit code.
1
#! /usr/bin/python
2
3
# Copyright (C) 2005 Canonical Ltd
4
0.1.33 by Martin Pool
add gpl text
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0.1.1 by Martin Pool
Check in old existing knit code.
18
19
# Author: Martin Pool <mbp@canonical.com>
20
21
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
22
"""Weave - storage of related text file versions"""
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
23
938 by Martin Pool
- various optimizations to weave add code
24
0.1.58 by Martin Pool
doc
25
# XXX: If we do weaves this way, will a merge still behave the same
26
# way if it's done in a different order?  That's a pretty desirable
27
# property.
28
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
29
# TODO: Nothing here so far assumes the lines are really \n newlines,
30
# rather than being split up in some other way.  We could accomodate
31
# binaries, perhaps by naively splitting on \n or perhaps using
32
# something like a rolling checksum.
33
0.1.85 by Martin Pool
doc
34
# TODO: End marker for each version so we can stop reading?
0.1.69 by Martin Pool
Simple text-based format for storing weaves, cleaner than
35
36
# TODO: Check that no insertion occurs inside a deletion that was
37
# active in the version of the insertion.
38
912 by Martin Pool
- update todos for weave
39
# TODO: In addition to the SHA-1 check, perhaps have some code that
40
# checks structural constraints of the weave: ie that insertions are
41
# properly nested, that there is no text outside of an insertion, that
42
# insertions or deletions are not repeated, etc.
0.1.85 by Martin Pool
doc
43
918 by Martin Pool
- start doing new weave-merge algorithm
44
# TODO: Parallel-extract that passes back each line along with a
45
# description of which revisions include it.  Nice for checking all
1393.1.25 by Martin Pool
- comments in weave code
46
# shas or calculating stats in parallel.
918 by Martin Pool
- start doing new weave-merge algorithm
47
1082 by Martin Pool
- lift imports
48
# TODO: Using a single _extract routine and then processing the output
49
# is probably inefficient.  It's simple enough that we can afford to
50
# have slight specializations for different ways its used: annotate,
51
# basis for add, get, etc.
52
1185.16.13 by Martin Pool
todo
53
# TODO: Probably the API should work only in names to hide the integer
54
# indexes from the user.
1083 by Martin Pool
- add space to store revision-id in weave files
55
1328 by Martin Pool
- slight refactoring of weave code
56
# TODO: Is there any potential performance win by having an add()
57
# variant that is passed a pre-cooked version of the single basis
58
# version?
59
1185.16.13 by Martin Pool
todo
60
# TODO: Reweave can possibly be made faster by remembering diffs
61
# where the basis and destination are unchanged.
62
63
# FIXME: Sometimes we will be given a parents list for a revision
64
# that includes some redundant parents (i.e. already a parent of 
65
# something in the list.)  We should eliminate them.  This can 
66
# be done fairly efficiently because the sequence numbers constrain
67
# the possible relationships.
1083 by Martin Pool
- add space to store revision-id in weave files
68
1082 by Martin Pool
- lift imports
69
70
import sha
1322 by Martin Pool
- tidy up import
71
from difflib import SequenceMatcher
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
72
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
73
from bzrlib.trace import mutter
1185.16.116 by mbp at sourcefrog
Move weave errors into bzrlib.errors and make consistent with new system.
74
from bzrlib.errors import WeaveError, WeaveFormatError, WeaveParentMismatch, \
75
        WeaveRevisionNotPresent, WeaveRevisionAlreadyPresent
1185.16.117 by mbp at sourcefrog
Reweave in topological-sort order.
76
from bzrlib.tsort import topo_sort
1185.16.116 by mbp at sourcefrog
Move weave errors into bzrlib.errors and make consistent with new system.
77
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
78
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
79
class Weave(object):
80
    """weave - versioned text file storage.
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
81
    
0.1.72 by Martin Pool
Go back to weave lines normally having newlines at the end.
82
    A Weave manages versions of line-based text files, keeping track
83
    of the originating version for each line.
84
85
    To clients the "lines" of the file are represented as a list of strings.
86
    These strings  will typically have terminal newline characters, but
87
    this is not required.  In particular files commonly do not have a newline
88
    at the end of the file.
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
89
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
90
    Texts can be identified in either of two ways:
91
92
    * a nonnegative index number.
93
1324 by Martin Pool
- doc
94
    * a version-id string.
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
95
0.1.38 by Martin Pool
Rename knit to weave. (I don't think there's an existing module called weave.)
96
    Typically the index number will be valid only inside this weave and
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
97
    the version-id is used to reference it in the larger world.
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
98
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
99
    The weave is represented as a list mixing edit instructions and
944 by Martin Pool
- refactor member names in Weave code
100
    literal text.  Each entry in _weave can be either a string (or
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
101
    unicode), or a tuple.  If a string, it means that the given line
102
    should be output in the currently active revisions.
103
104
    If a tuple, it gives a processing instruction saying in which
105
    revisions the enclosed lines are active.  The tuple has the form
106
    (instruction, version).
107
108
    The instruction can be '{' or '}' for an insertion block, and '['
109
    and ']' for a deletion block respectively.  The version is the
0.1.45 by Martin Pool
doc
110
    integer version index.  There is no replace operator, only deletes
1075 by Martin Pool
- don't store redundant version number at end of insert blocks
111
    and inserts.  For '}', the end of an insertion, there is no
112
    version parameter because it always closes the most recently
113
    opened insertion.
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
114
0.1.41 by Martin Pool
Doc
115
    Constraints/notes:
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
116
117
    * A later version can delete lines that were introduced by any
118
      number of ancestor versions; this implies that deletion
119
      instructions can span insertion blocks without regard to the
120
      insertion block's nesting.
121
0.1.41 by Martin Pool
Doc
122
    * Similarly, deletions need not be properly nested with regard to
123
      each other, because they might have been generated by
124
      independent revisions.
125
0.1.45 by Martin Pool
doc
126
    * Insertions are always made by inserting a new bracketed block
127
      into a single point in the previous weave.  This implies they
128
      can nest but not overlap, and the nesting must always have later
129
      insertions on the inside.
130
0.1.41 by Martin Pool
Doc
131
    * It doesn't seem very useful to have an active insertion
132
      inside an inactive insertion, but it might happen.
0.1.45 by Martin Pool
doc
133
      
0.1.41 by Martin Pool
Doc
134
    * Therefore, all instructions are always"considered"; that
135
      is passed onto and off the stack.  An outer inactive block
136
      doesn't disable an inner block.
137
138
    * Lines are enabled if the most recent enclosing insertion is
139
      active and none of the enclosing deletions are active.
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
140
0.1.49 by Martin Pool
Add another constraint: revisions should not delete text that they
141
    * There is no point having a deletion directly inside its own
142
      insertion; you might as well just not write it.  And there
143
      should be no way to get an earlier version deleting a later
144
      version.
145
944 by Martin Pool
- refactor member names in Weave code
146
    _weave
147
        Text of the weave; list of control instruction tuples and strings.
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
148
944 by Martin Pool
- refactor member names in Weave code
149
    _parents
892 by Martin Pool
- weave stores only direct parents, and calculates and memoizes expansion as needed
150
        List of parents, indexed by version number.
151
        It is only necessary to store the minimal set of parents for
152
        each version; the parent's parents are implied.
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
153
0.1.89 by Martin Pool
Store SHA1 in weave file for later verification
154
    _sha1s
1083 by Martin Pool
- add space to store revision-id in weave files
155
        List of hex SHA-1 of each version.
156
157
    _names
158
        List of symbolic names for each version.  Each should be unique.
159
160
    _name_map
161
        For each name, the version number.
1209 by Martin Pool
- Add Weave._weave_name for debugging purposes
162
163
    _weave_name
164
        Descriptive name of this weave; typically the filename if known.
165
        Set by read_weave.
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
166
    """
938 by Martin Pool
- various optimizations to weave add code
167
1209 by Martin Pool
- Add Weave._weave_name for debugging purposes
168
    __slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map',
169
                 '_weave_name']
938 by Martin Pool
- various optimizations to weave add code
170
    
1209 by Martin Pool
- Add Weave._weave_name for debugging purposes
171
    def __init__(self, weave_name=None):
944 by Martin Pool
- refactor member names in Weave code
172
        self._weave = []
173
        self._parents = []
0.1.89 by Martin Pool
Store SHA1 in weave file for later verification
174
        self._sha1s = []
1083 by Martin Pool
- add space to store revision-id in weave files
175
        self._names = []
176
        self._name_map = {}
1209 by Martin Pool
- Add Weave._weave_name for debugging purposes
177
        self._weave_name = weave_name
0.1.60 by Martin Pool
Weave eq and ne methods
178
179
1393.1.51 by Martin Pool
- new Weave.copy()
180
    def copy(self):
181
        """Return a deep copy of self.
182
        
183
        The copy can be modified without affecting the original weave."""
184
        other = Weave()
185
        other._weave = self._weave[:]
186
        other._parents = self._parents[:]
187
        other._sha1s = self._sha1s[:]
188
        other._names = self._names[:]
189
        other._name_map = self._name_map.copy()
190
        other._weave_name = self._weave_name
191
        return other
192
0.1.60 by Martin Pool
Weave eq and ne methods
193
    def __eq__(self, other):
194
        if not isinstance(other, Weave):
195
            return False
944 by Martin Pool
- refactor member names in Weave code
196
        return self._parents == other._parents \
1083 by Martin Pool
- add space to store revision-id in weave files
197
               and self._weave == other._weave \
198
               and self._sha1s == other._sha1s 
199
0.1.60 by Martin Pool
Weave eq and ne methods
200
    
201
    def __ne__(self, other):
202
        return not self.__eq__(other)
203
1185.16.124 by Martin Pool
Add Weave.__contains__.
204
    def __contains__(self, name):
205
        return self._name_map.has_key(name)
1083 by Martin Pool
- add space to store revision-id in weave files
206
1269 by Martin Pool
- some weave operations automatically look up symbolic names if supplied
207
    def maybe_lookup(self, name_or_index):
208
        """Convert possible symbolic name to index, or pass through indexes."""
209
        if isinstance(name_or_index, (int, long)):
210
            return name_or_index
211
        else:
212
            return self.lookup(name_or_index)
213
214
        
1083 by Martin Pool
- add space to store revision-id in weave files
215
    def lookup(self, name):
1269 by Martin Pool
- some weave operations automatically look up symbolic names if supplied
216
        """Convert symbolic version name to index."""
1083 by Martin Pool
- add space to store revision-id in weave files
217
        try:
218
            return self._name_map[name]
219
        except KeyError:
1185.16.116 by mbp at sourcefrog
Move weave errors into bzrlib.errors and make consistent with new system.
220
            raise WeaveRevisionNotPresent(name, self)
1083 by Martin Pool
- add space to store revision-id in weave files
221
1185.16.104 by mbp at sourcefrog
Add Weave.names()
222
    def names(self):
1185.16.105 by mbp at sourcefrog
- fix Weave.names()
223
        return self._names[:]
1229 by Martin Pool
- new Weave.idx_to_name and .parents methods
224
1393.1.49 by Martin Pool
- add Weave._check_consistent_with
225
    def iter_names(self):
226
        """Yield a list of all names in this weave."""
227
        return iter(self._names)
228
1229 by Martin Pool
- new Weave.idx_to_name and .parents methods
229
    def idx_to_name(self, version):
230
        return self._names[version]
231
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
232
    def _check_repeated_add(self, name, parents, text, sha1):
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
233
        """Check that a duplicated add is OK.
234
235
        If it is, return the (old) index; otherwise raise an exception.
236
        """
237
        idx = self.lookup(name)
1185.16.116 by mbp at sourcefrog
Move weave errors into bzrlib.errors and make consistent with new system.
238
        if sorted(self._parents[idx]) != sorted(parents) \
239
            or sha1 != self._sha1s[idx]:
240
            raise WeaveRevisionAlreadyPresent(name, self)
1237 by Martin Pool
- allow the same version to be repeatedly added to a weave
241
        return idx
242
        
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
243
    def add(self, name, parents, text, sha1=None):
0.1.4 by Martin Pool
Start indexing knits by both integer and version string.
244
        """Add a single text on top of the weave.
0.1.36 by Martin Pool
doc
245
  
0.1.26 by Martin Pool
Refactor parameters to add command
246
        Returns the index number of the newly added version.
247
1083 by Martin Pool
- add space to store revision-id in weave files
248
        name
249
            Symbolic name for this version.
250
            (Typically the revision-id of the revision that added it.)
251
0.1.26 by Martin Pool
Refactor parameters to add command
252
        parents
892 by Martin Pool
- weave stores only direct parents, and calculates and memoizes expansion as needed
253
            List or set of direct parent version numbers.
254
            
0.1.26 by Martin Pool
Refactor parameters to add command
255
        text
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
256
            Sequence of lines to be added in the new version.
257
258
        sha -- SHA-1 of the file, if known.  This is trusted to be
259
            correct if supplied.
260
        """
1393.1.4 by Martin Pool
- weave tool now finds bzrlib if it's not on the default path
261
        from bzrlib.osutils import sha_strings
938 by Martin Pool
- various optimizations to weave add code
262
1083 by Martin Pool
- add space to store revision-id in weave files
263
        assert isinstance(name, basestring)
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
264
        if sha1 is None:
265
            sha1 = sha_strings(text)
1083 by Martin Pool
- add space to store revision-id in weave files
266
        if name in self._name_map:
1323 by Martin Pool
- caller can pass SHA-1 to Weave.add for efficiency
267
            return self._check_repeated_add(name, parents, text, sha1)
1269 by Martin Pool
- some weave operations automatically look up symbolic names if supplied
268
269
        parents = map(self.maybe_lookup, parents)
938 by Martin Pool
- various optimizations to weave add code
270
        self._check_versions(parents)
0.1.82 by Martin Pool
Small weave optimizations
271
        ## self._check_lines(text)
944 by Martin Pool
- refactor member names in Weave code
272
        new_version = len(self._parents)
0.1.5 by Martin Pool
Add test for storing two text versions.
273
0.1.89 by Martin Pool
Store SHA1 in weave file for later verification
274
1083 by Martin Pool
- add space to store revision-id in weave files
275
        # if we abort after here the (in-memory) weave will be corrupt because only
276
        # some fields are updated
277
        self._parents.append(parents[:])
0.1.89 by Martin Pool
Store SHA1 in weave file for later verification
278
        self._sha1s.append(sha1)
1083 by Martin Pool
- add space to store revision-id in weave files
279
        self._names.append(name)
280
        self._name_map[name] = new_version
938 by Martin Pool
- various optimizations to weave add code
281
282
            
283
        if not parents:
284
            # special case; adding with no parents revision; can do
285
            # this more quickly by just appending unconditionally.
286
            # even more specially, if we're adding an empty text we
287
            # need do nothing at all.
288
            if text:
944 by Martin Pool
- refactor member names in Weave code
289
                self._weave.append(('{', new_version))
290
                self._weave.extend(text)
1075 by Martin Pool
- don't store redundant version number at end of insert blocks
291
                self._weave.append(('}', None))
938 by Martin Pool
- various optimizations to weave add code
292
        
293
            return new_version
294
941 by Martin Pool
- allow for parents specified to Weave.add to be a set
295
        if len(parents) == 1:
296
            pv = list(parents)[0]
297
            if sha1 == self._sha1s[pv]:
298
                # special case: same as the single parent
299
                return new_version
938 by Martin Pool
- various optimizations to weave add code
300
            
301
302
        ancestors = self.inclusions(parents)
303
944 by Martin Pool
- refactor member names in Weave code
304
        l = self._weave
938 by Martin Pool
- various optimizations to weave add code
305
306
        # basis a list of (origin, lineno, line)
307
        basis_lineno = []
308
        basis_lines = []
309
        for origin, lineno, line in self._extract(ancestors):
310
            basis_lineno.append(lineno)
311
            basis_lines.append(line)
312
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
313
        # another small special case: a merge, producing the same text
314
        # as auto-merge
938 by Martin Pool
- various optimizations to weave add code
315
        if text == basis_lines:
316
            return new_version            
317
318
        # add a sentinal, because we can also match against the final line
944 by Martin Pool
- refactor member names in Weave code
319
        basis_lineno.append(len(self._weave))
938 by Martin Pool
- various optimizations to weave add code
320
321
        # XXX: which line of the weave should we really consider
322
        # matches the end of the file?  the current code says it's the
323
        # last line of the weave?
324
325
        #print 'basis_lines:', basis_lines
326
        #print 'new_lines:  ', lines
327
328
        s = SequenceMatcher(None, basis_lines, text)
329
330
        # offset gives the number of lines that have been inserted
331
        # into the weave up to the current point; if the original edit instruction
332
        # says to change line A then we actually change (A+offset)
333
        offset = 0
334
335
        for tag, i1, i2, j1, j2 in s.get_opcodes():
336
            # i1,i2 are given in offsets within basis_lines; we need to map them
337
            # back to offsets within the entire weave
338
            #print 'raw match', tag, i1, i2, j1, j2
339
            if tag == 'equal':
340
                continue
341
342
            i1 = basis_lineno[i1]
343
            i2 = basis_lineno[i2]
344
345
            assert 0 <= j1 <= j2 <= len(text)
346
347
            #print tag, i1, i2, j1, j2
348
349
            # the deletion and insertion are handled separately.
350
            # first delete the region.
351
            if i1 != i2:
944 by Martin Pool
- refactor member names in Weave code
352
                self._weave.insert(i1+offset, ('[', new_version))
353
                self._weave.insert(i2+offset+1, (']', new_version))
938 by Martin Pool
- various optimizations to weave add code
354
                offset += 2
355
356
            if j1 != j2:
357
                # there may have been a deletion spanning up to
358
                # i2; we want to insert after this region to make sure
359
                # we don't destroy ourselves
360
                i = i2 + offset
944 by Martin Pool
- refactor member names in Weave code
361
                self._weave[i:i] = ([('{', new_version)] 
1075 by Martin Pool
- don't store redundant version number at end of insert blocks
362
                                    + text[j1:j2] 
363
                                    + [('}', None)])
938 by Martin Pool
- various optimizations to weave add code
364
                offset += 2 + (j2 - j1)
365
366
        return new_version
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
367
1092.2.22 by Robert Collins
text_version and name_version unification looking reasonable
368
    def add_identical(self, old_rev_id, new_rev_id, parents):
369
        """Add an identical text to old_rev_id as new_rev_id."""
370
        old_lines = self.get(self.lookup(old_rev_id))
371
        self.add(new_rev_id, parents, old_lines)
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
372
0.1.78 by Martin Pool
Rename Weave.get_included to inclusions and getiter to get_iter
373
    def inclusions(self, versions):
893 by Martin Pool
- Refactor weave calculation of inclusions
374
        """Return set of all ancestors of given version(s)."""
928 by Martin Pool
- go back to using plain builtin set()
375
        i = set(versions)
1328 by Martin Pool
- slight refactoring of weave code
376
        for v in xrange(max(versions), 0, -1):
377
            if v in i:
378
                # include all its parents
379
                i.update(self._parents[v])
380
        return i
381
        ## except IndexError:
382
        ##     raise ValueError("version %d not present in weave" % v)
0.1.77 by Martin Pool
New Weave.get_included() does transitive expansion
383
384
1229 by Martin Pool
- new Weave.idx_to_name and .parents methods
385
    def parents(self, version):
386
        return self._parents[version]
387
388
1393.1.69 by Martin Pool
- new Weave.parent_names
389
    def parent_names(self, version):
390
        """Return version names for parents of a version."""
391
        return map(self.idx_to_name, self._parents[self.lookup(version)])
392
393
890 by Martin Pool
- weave info should show minimal expression of parents
394
    def minimal_parents(self, version):
395
        """Find the minimal set of parents for the version."""
944 by Martin Pool
- refactor member names in Weave code
396
        included = self._parents[version]
890 by Martin Pool
- weave info should show minimal expression of parents
397
        if not included:
398
            return []
399
        
400
        li = list(included)
893 by Martin Pool
- Refactor weave calculation of inclusions
401
        li.sort(reverse=True)
890 by Martin Pool
- weave info should show minimal expression of parents
402
403
        mininc = []
928 by Martin Pool
- go back to using plain builtin set()
404
        gotit = set()
890 by Martin Pool
- weave info should show minimal expression of parents
405
406
        for pv in li:
407
            if pv not in gotit:
408
                mininc.append(pv)
893 by Martin Pool
- Refactor weave calculation of inclusions
409
                gotit.update(self.inclusions(pv))
890 by Martin Pool
- weave info should show minimal expression of parents
410
411
        assert mininc[0] >= 0
412
        assert mininc[-1] < version
413
        return mininc
414
415
0.1.75 by Martin Pool
Remove VerInfo class; just store sets directly in the list of
416
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
417
    def _check_lines(self, text):
418
        if not isinstance(text, list):
419
            raise ValueError("text should be a list, not %s" % type(text))
420
421
        for l in text:
422
            if not isinstance(l, basestring):
869 by Martin Pool
- more weave.py command line options
423
                raise ValueError("text line should be a string or unicode, not %s"
424
                                 % type(l))
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
425
        
426
427
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
428
    def _check_versions(self, indexes):
429
        """Check everything in the sequence of indexes is valid"""
430
        for i in indexes:
431
            try:
944 by Martin Pool
- refactor member names in Weave code
432
                self._parents[i]
0.1.27 by Martin Pool
Check that version numbers passed in are reasonable
433
            except IndexError:
434
                raise IndexError("invalid version number %r" % i)
435
0.1.2 by Martin Pool
Import testsweet module adapted from bzr.
436
    
1269 by Martin Pool
- some weave operations automatically look up symbolic names if supplied
437
    def annotate(self, name_or_index):
438
        return list(self.annotate_iter(name_or_index))
439
440
441
    def annotate_iter(self, name_or_index):
0.1.7 by Martin Pool
Add trivial annotate text
442
        """Yield list of (index-id, line) pairs for the specified version.
443
444
        The index indicates when the line originated in the weave."""
1269 by Martin Pool
- some weave operations automatically look up symbolic names if supplied
445
        incls = [self.maybe_lookup(name_or_index)]
446
        for origin, lineno, text in self._extract(incls):
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
447
            yield origin, text
0.1.22 by Martin Pool
Calculate delta for new versions relative to a set of parent versions.
448
918 by Martin Pool
- start doing new weave-merge algorithm
449
    def _walk(self):
450
        """Walk the weave.
451
452
        Yields sequence of
453
        (lineno, insert, deletes, text)
454
        for each literal line.
455
        """
456
        
457
        istack = []
928 by Martin Pool
- go back to using plain builtin set()
458
        dset = set()
918 by Martin Pool
- start doing new weave-merge algorithm
459
460
        lineno = 0         # line of weave, 0-based
461
944 by Martin Pool
- refactor member names in Weave code
462
        for l in self._weave:
918 by Martin Pool
- start doing new weave-merge algorithm
463
            if isinstance(l, tuple):
464
                c, v = l
465
                isactive = None
466
                if c == '{':
467
                    istack.append(v)
468
                elif c == '}':
1075 by Martin Pool
- don't store redundant version number at end of insert blocks
469
                    istack.pop()
918 by Martin Pool
- start doing new weave-merge algorithm
470
                elif c == '[':
926 by Martin Pool
- update more weave code to use intsets
471
                    assert v not in dset
472
                    dset.add(v)
918 by Martin Pool
- start doing new weave-merge algorithm
473
                elif c == ']':
926 by Martin Pool
- update more weave code to use intsets
474
                    dset.remove(v)
918 by Martin Pool
- start doing new weave-merge algorithm
475
                else:
1185.16.116 by mbp at sourcefrog
Move weave errors into bzrlib.errors and make consistent with new system.
476
                    raise WeaveFormatError('unexpected instruction %r' % v)
918 by Martin Pool
- start doing new weave-merge algorithm
477
            else:
478
                assert isinstance(l, basestring)
479
                assert istack
480
                yield lineno, istack[-1], dset, l
481
            lineno += 1
482
483
484
893 by Martin Pool
- Refactor weave calculation of inclusions
485
    def _extract(self, versions):
0.1.20 by Martin Pool
Factor out Knit.extract() method
486
        """Yield annotation of lines in included set.
487
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
488
        Yields a sequence of tuples (origin, lineno, text), where
489
        origin is the origin version, lineno the index in the weave,
490
        and text the text of the line.
491
0.1.20 by Martin Pool
Factor out Knit.extract() method
492
        The set typically but not necessarily corresponds to a version.
493
        """
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
494
        for i in versions:
495
            if not isinstance(i, int):
496
                raise ValueError(i)
497
            
893 by Martin Pool
- Refactor weave calculation of inclusions
498
        included = self.inclusions(versions)
881 by Martin Pool
- faster weave extraction
499
500
        istack = []
928 by Martin Pool
- go back to using plain builtin set()
501
        dset = set()
0.1.48 by Martin Pool
Basic parsing of delete instructions.
502
503
        lineno = 0         # line of weave, 0-based
891 by Martin Pool
- fix up refactoring of weave
504
894 by Martin Pool
- small optimization for weave extract
505
        isactive = None
0.1.85 by Martin Pool
doc
506
931 by Martin Pool
- experiment with making Weave._extract() return a list, not a generator - slightly faster
507
        result = []
508
0.1.63 by Martin Pool
Abbreviate WeaveFormatError in some code
509
        WFE = WeaveFormatError
0.1.95 by Martin Pool
- preliminary merge conflict detection
510
944 by Martin Pool
- refactor member names in Weave code
511
        for l in self._weave:
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
512
            if isinstance(l, tuple):
513
                c, v = l
894 by Martin Pool
- small optimization for weave extract
514
                isactive = None
891 by Martin Pool
- fix up refactoring of weave
515
                if c == '{':
516
                    assert v not in istack
517
                    istack.append(v)
518
                elif c == '}':
1075 by Martin Pool
- don't store redundant version number at end of insert blocks
519
                    istack.pop()
891 by Martin Pool
- fix up refactoring of weave
520
                elif c == '[':
521
                    if v in included:
881 by Martin Pool
- faster weave extraction
522
                        assert v not in dset
0.1.48 by Martin Pool
Basic parsing of delete instructions.
523
                        dset.add(v)
891 by Martin Pool
- fix up refactoring of weave
524
                else:
525
                    assert c == ']'
526
                    if v in included:
881 by Martin Pool
- faster weave extraction
527
                        assert v in dset
0.1.48 by Martin Pool
Basic parsing of delete instructions.
528
                        dset.remove(v)
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
529
            else:
530
                assert isinstance(l, basestring)
894 by Martin Pool
- small optimization for weave extract
531
                if isactive is None:
532
                    isactive = (not dset) and istack and (istack[-1] in included)
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
533
                if isactive:
931 by Martin Pool
- experiment with making Weave._extract() return a list, not a generator - slightly faster
534
                    result.append((istack[-1], lineno, l))
0.1.39 by Martin Pool
Change to a more realistic weave structure which can represent insertions and
535
            lineno += 1
0.1.46 by Martin Pool
More constraints on structure of weave, and checks that they work
536
        if istack:
1185.16.116 by mbp at sourcefrog
Move weave errors into bzrlib.errors and make consistent with new system.
537
            raise WeaveFormatError("unclosed insertion blocks "
538
                    "at end of weave: %s" % istack)
0.1.48 by Martin Pool
Basic parsing of delete instructions.
539
        if dset:
1185.16.116 by mbp at sourcefrog
Move weave errors into bzrlib.errors and make consistent with new system.
540
            raise WeaveFormatError("unclosed deletion blocks at end of weave: %s"
541
                                   % dset)
931 by Martin Pool
- experiment with making Weave._extract() return a list, not a generator - slightly faster
542
        return result
543
0.1.7 by Martin Pool
Add trivial annotate text
544
1269 by Martin Pool
- some weave operations automatically look up symbolic names if supplied
545
    def get_iter(self, name_or_index):
0.1.5 by Martin Pool
Add test for storing two text versions.
546
        """Yield lines for the specified version."""
1269 by Martin Pool
- some weave operations automatically look up symbolic names if supplied
547
        incls = [self.maybe_lookup(name_or_index)]
548
        for origin, lineno, line in self._extract(incls):
0.1.8 by Martin Pool
Unify get/annotate code
549
            yield line
0.1.5 by Martin Pool
Add test for storing two text versions.
550
551
1369 by Martin Pool
- try to avoid redundant conversion of strings when retrieving from weaves
552
    def get_text(self, name_or_index):
553
        return ''.join(self.get_iter(name_or_index))
554
        assert isinstance(version, int)
555
556
557
    def get_lines(self, name_or_index):
1269 by Martin Pool
- some weave operations automatically look up symbolic names if supplied
558
        return list(self.get_iter(name_or_index))
0.1.1 by Martin Pool
Check in old existing knit code.
559
560
1369 by Martin Pool
- try to avoid redundant conversion of strings when retrieving from weaves
561
    get = get_lines
562
563
0.1.95 by Martin Pool
- preliminary merge conflict detection
564
    def mash_iter(self, included):
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
565
        """Return composed version of multiple included versions."""
1338 by Martin Pool
- Weave.mash_iter optionally takes names rather than indexes
566
        included = map(self.maybe_lookup, included)
893 by Martin Pool
- Refactor weave calculation of inclusions
567
        for origin, lineno, text in self._extract(included):
0.1.65 by Martin Pool
Add Weave.merge_iter to get automerged lines
568
            yield text
569
570
0.1.11 by Martin Pool
Add Knit.dump method
571
    def dump(self, to_file):
572
        from pprint import pprint
944 by Martin Pool
- refactor member names in Weave code
573
        print >>to_file, "Weave._weave = ",
574
        pprint(self._weave, to_file)
575
        print >>to_file, "Weave._parents = ",
576
        pprint(self._parents, to_file)
0.1.11 by Martin Pool
Add Knit.dump method
577
578
0.1.91 by Martin Pool
Update Weave.check
579
580
    def numversions(self):
944 by Martin Pool
- refactor member names in Weave code
581
        l = len(self._parents)
0.1.91 by Martin Pool
Update Weave.check
582
        assert l == len(self._sha1s)
583
        return l
584
585
946 by Martin Pool
- weave info only shows the weave headers, doesn't extract every version:
586
    def __len__(self):
587
        return self.numversions()
588
589
894 by Martin Pool
- small optimization for weave extract
590
    def check(self, progress_bar=None):
0.1.91 by Martin Pool
Update Weave.check
591
        # check no circular inclusions
592
        for version in range(self.numversions()):
944 by Martin Pool
- refactor member names in Weave code
593
            inclusions = list(self._parents[version])
0.1.91 by Martin Pool
Update Weave.check
594
            if inclusions:
595
                inclusions.sort()
596
                if inclusions[-1] >= version:
0.1.47 by Martin Pool
New WeaveError and WeaveFormatError rather than assertions.
597
                    raise WeaveFormatError("invalid included version %d for index %d"
0.1.91 by Martin Pool
Update Weave.check
598
                                           % (inclusions[-1], version))
599
600
        # try extracting all versions; this is a bit slow and parallel
601
        # extraction could be used
894 by Martin Pool
- small optimization for weave extract
602
        nv = self.numversions()
603
        for version in range(nv):
604
            if progress_bar:
605
                progress_bar.update('checking text', version, nv)
0.1.91 by Martin Pool
Update Weave.check
606
            s = sha.new()
607
            for l in self.get_iter(version):
608
                s.update(l)
609
            hd = s.hexdigest()
610
            expected = self._sha1s[version]
611
            if hd != expected:
612
                raise WeaveError("mismatched sha1 for version %d; "
613
                                 "got %s, expected %s"
614
                                 % (version, hd, expected))
0.1.18 by Martin Pool
Better Knit.dump method
615
881 by Martin Pool
- faster weave extraction
616
        # TODO: check insertions are properly nested, that there are
617
        # no lines outside of insertion blocks, that deletions are
618
        # properly paired, etc.
619
0.1.13 by Martin Pool
Knit structure now allows for versions to include the lines present in other
620
621
0.1.95 by Martin Pool
- preliminary merge conflict detection
622
    def merge(self, merge_versions):
623
        """Automerge and mark conflicts between versions.
624
625
        This returns a sequence, each entry describing alternatives
626
        for a chunk of the file.  Each of the alternatives is given as
627
        a list of lines.
628
629
        If there is a chunk of the file where there's no diagreement,
630
        only one alternative is given.
631
        """
632
        # approach: find the included versions common to all the
633
        # merged versions
634
        raise NotImplementedError()
635
636
637
0.1.21 by Martin Pool
Start computing a delta to insert a new revision
638
    def _delta(self, included, lines):
639
        """Return changes from basis to new revision.
640
641
        The old text for comparison is the union of included revisions.
642
643
        This is used in inserting a new text.
0.1.22 by Martin Pool
Calculate delta for new versions relative to a set of parent versions.
644
0.1.55 by Martin Pool
doc
645
        Delta is returned as a sequence of
646
        (weave1, weave2, newlines).
647
648
        This indicates that weave1:weave2 of the old weave should be
0.1.22 by Martin Pool
Calculate delta for new versions relative to a set of parent versions.
649
        replaced by the sequence of lines in newlines.  Note that
650
        these line numbers are positions in the total weave and don't
651
        correspond to the lines in any extracted version, or even the
652
        extracted union of included versions.
653
654
        If line1=line2, this is a pure insert; if newlines=[] this is a
655
        pure delete.  (Similar to difflib.)
0.1.21 by Martin Pool
Start computing a delta to insert a new revision
656
        """
1393.1.47 by Martin Pool
- Weave._delta is not implemented at the moment
657
        raise NotImplementedError()
0.1.1 by Martin Pool
Check in old existing knit code.
658
918 by Martin Pool
- start doing new weave-merge algorithm
659
            
660
    def plan_merge(self, ver_a, ver_b):
661
        """Return pseudo-annotation indicating how the two versions merge.
662
663
        This is computed between versions a and b and their common
664
        base.
665
666
        Weave lines present in none of them are skipped entirely.
667
        """
926 by Martin Pool
- update more weave code to use intsets
668
        inc_a = self.inclusions([ver_a])
669
        inc_b = self.inclusions([ver_b])
918 by Martin Pool
- start doing new weave-merge algorithm
670
        inc_c = inc_a & inc_b
671
672
        for lineno, insert, deleteset, line in self._walk():
673
            if deleteset & inc_c:
674
                # killed in parent; can't be in either a or b
675
                # not relevant to our work
676
                yield 'killed-base', line
926 by Martin Pool
- update more weave code to use intsets
677
            elif insert in inc_c:
918 by Martin Pool
- start doing new weave-merge algorithm
678
                # was inserted in base
679
                killed_a = bool(deleteset & inc_a)
680
                killed_b = bool(deleteset & inc_b)
681
                if killed_a and killed_b:
682
                    yield 'killed-both', line
683
                elif killed_a:
684
                    yield 'killed-a', line
685
                elif killed_b:
686
                    yield 'killed-b', line
687
                else:
688
                    yield 'unchanged', line
926 by Martin Pool
- update more weave code to use intsets
689
            elif insert in inc_a:
918 by Martin Pool
- start doing new weave-merge algorithm
690
                if deleteset & inc_a:
691
                    yield 'ghost-a', line
692
                else:
693
                    # new in A; not in B
694
                    yield 'new-a', line
926 by Martin Pool
- update more weave code to use intsets
695
            elif insert in inc_b:
918 by Martin Pool
- start doing new weave-merge algorithm
696
                if deleteset & inc_b:
697
                    yield 'ghost-b', line
698
                else:
699
                    yield 'new-b', line
700
            else:
701
                # not in either revision
702
                yield 'irrelevant', line
703
919 by Martin Pool
- more development of weave-merge
704
        yield 'unchanged', ''           # terminator
705
706
707
708
    def weave_merge(self, plan):
709
        lines_a = []
710
        lines_b = []
711
        ch_a = ch_b = False
712
713
        for state, line in plan:
714
            if state == 'unchanged' or state == 'killed-both':
715
                # resync and flush queued conflicts changes if any
716
                if not lines_a and not lines_b:
717
                    pass
718
                elif ch_a and not ch_b:
719
                    # one-sided change:                    
720
                    for l in lines_a: yield l
721
                elif ch_b and not ch_a:
722
                    for l in lines_b: yield l
723
                elif lines_a == lines_b:
724
                    for l in lines_a: yield l
725
                else:
1185.12.86 by Aaron Bentley
Switched to standard 7-char conflict markers
726
                    yield '<<<<<<<\n'
919 by Martin Pool
- more development of weave-merge
727
                    for l in lines_a: yield l
1185.12.86 by Aaron Bentley
Switched to standard 7-char conflict markers
728
                    yield '=======\n'
919 by Martin Pool
- more development of weave-merge
729
                    for l in lines_b: yield l
1185.12.86 by Aaron Bentley
Switched to standard 7-char conflict markers
730
                    yield '>>>>>>>\n'
919 by Martin Pool
- more development of weave-merge
731
732
                del lines_a[:]
733
                del lines_b[:]
734
                ch_a = ch_b = False
735
                
736
            if state == 'unchanged':
737
                if line:
738
                    yield line
739
            elif state == 'killed-a':
740
                ch_a = True
741
                lines_b.append(line)
742
            elif state == 'killed-b':
743
                ch_b = True
744
                lines_a.append(line)
745
            elif state == 'new-a':
746
                ch_a = True
747
                lines_a.append(line)
748
            elif state == 'new-b':
749
                ch_b = True
750
                lines_b.append(line)
751
            else:
920 by Martin Pool
- add more test cases for weave_merge
752
                assert state in ('irrelevant', 'ghost-a', 'ghost-b', 'killed-base',
753
                                 'killed-both'), \
919 by Martin Pool
- more development of weave-merge
754
                       state
755
756
                
1393.1.48 by Martin Pool
- Add stub Weave.join() method
757
    def join(self, other):
758
        """Integrate versions from other into this weave.
759
1393.1.49 by Martin Pool
- add Weave._check_consistent_with
760
        The resulting weave contains all the history of both weaves; 
761
        any version you could retrieve from either self or other can be 
762
        retrieved from self after this call.
1393.1.48 by Martin Pool
- Add stub Weave.join() method
763
1393.1.49 by Martin Pool
- add Weave._check_consistent_with
764
        It is illegal for the two weaves to contain different values 
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
765
        or different parents for any version.  See also reweave().
1393.1.48 by Martin Pool
- Add stub Weave.join() method
766
        """
767
        if other.numversions() == 0:
768
            return          # nothing to update, easy
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
769
        # two loops so that we do not change ourselves before verifying it
770
        # will be ok
1393.1.50 by Martin Pool
- more development of Weave.join()
771
        # work through in index order to make sure we get all dependencies
772
        for other_idx, name in enumerate(other._names):
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
773
            if self._check_version_consistent(other, other_idx, name):
774
                continue
775
        for other_idx, name in enumerate(other._names):
1393.1.50 by Martin Pool
- more development of Weave.join()
776
            # TODO: If all the parents of the other version are already 
777
            # present then we can avoid some work by just taking the delta
778
            # and adjusting the offsets.
1393.1.51 by Martin Pool
- new Weave.copy()
779
            new_parents = self._imported_parents(other, other_idx)
1393.1.50 by Martin Pool
- more development of Weave.join()
780
            lines = other.get_lines(other_idx)
781
            sha1 = other._sha1s[other_idx]
782
            self.add(name, new_parents, lines, sha1)
783
1393.1.51 by Martin Pool
- new Weave.copy()
784
785
    def _imported_parents(self, other, other_idx):
786
        """Return list of parents in self corresponding to indexes in other."""
787
        new_parents = []
788
        for parent_idx in other._parents[other_idx]:
789
            parent_name = other._names[parent_idx]
790
            if parent_name not in self._names:
791
                # should not be possible
792
                raise WeaveError("missing parent {%s} of {%s} in %r" 
793
                                 % (parent_name, other._name_map[other_idx], self))
794
            new_parents.append(self._name_map[parent_name])
795
        return new_parents
796
1393.1.50 by Martin Pool
- more development of Weave.join()
797
    def _check_version_consistent(self, other, other_idx, name):
798
        """Check if a version in consistent in this and other.
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
799
800
        To be consistent it must have:
801
802
         * the same text
803
         * the same direct parents (by name, not index, and disregarding
804
           order)
1393.1.50 by Martin Pool
- more development of Weave.join()
805
        
806
        If present & correct return True;
807
        if not present in self return False; 
808
        if inconsistent raise error."""
809
        this_idx = self._name_map.get(name, -1)
810
        if this_idx != -1:
811
            if self._sha1s[this_idx] != other._sha1s[other_idx]:
1393.1.66 by Martin Pool
- fix join of weaves where parents occur at different offsets
812
                raise WeaveError("inconsistent texts for version {%s} "
813
                                 "when joining weaves"
814
                                 % (name))
815
            self_parents = self._parents[this_idx]
816
            other_parents = other._parents[other_idx]
817
            n1 = [self._names[i] for i in self_parents]
818
            n2 = [other._names[i] for i in other_parents]
819
            n1.sort()
820
            n2.sort()
821
            if n1 != n2:
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
822
                raise WeaveParentMismatch("inconsistent parents "
823
                    "for version {%s}: %s vs %s" % (name, n1, n2))
1393.1.50 by Martin Pool
- more development of Weave.join()
824
            else:
825
                return True         # ok!
826
        else:
827
            return False
918 by Martin Pool
- start doing new weave-merge algorithm
828
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
829
    def reweave(self, other):
830
        """Reweave self with other."""
831
        new_weave = reweave(self, other)
832
        for attr in self.__slots__:
833
            setattr(self, attr, getattr(new_weave, attr))
834
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
835
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
836
def reweave(wa, wb):
837
    """Combine two weaves and return the result.
838
839
    This works even if a revision R has different parents in 
840
    wa and wb.  In the resulting weave all the parents are given.
841
842
    This is done by just building up a new weave, maintaining ordering 
843
    of the versions in the two inputs.  More efficient approaches
844
    might be possible but it should only be necessary to do 
845
    this operation rarely, when a new previously ghost version is 
846
    inserted.
847
    """
848
    wr = Weave()
849
    ia = ib = 0
850
    queue_a = range(wa.numversions())
851
    queue_b = range(wb.numversions())
852
    # first determine combined parents of all versions
853
    # map from version name -> all parent names
854
    combined_parents = _reweave_parent_graphs(wa, wb)
855
    mutter("combined parents: %r", combined_parents)
1185.16.117 by mbp at sourcefrog
Reweave in topological-sort order.
856
    order = topo_sort(combined_parents.iteritems())
1393.1.68 by Martin Pool
- add reweave that joins with ghosts
857
    mutter("order to reweave: %r", order)
858
    for name in order:
859
        if name in wa._name_map:
860
            lines = wa.get_lines(name)
861
            if name in wb._name_map:
862
                assert lines == wb.get_lines(name)
863
        else:
864
            lines = wb.get_lines(name)
865
        wr.add(name, combined_parents[name], lines)
866
    return wr
867
868
869
def _reweave_parent_graphs(wa, wb):
870
    """Return combined parent ancestry for two weaves.
871
    
872
    Returned as a list of (version_name, set(parent_names))"""
873
    combined = {}
874
    for weave in [wa, wb]:
875
        for idx, name in enumerate(weave._names):
876
            p = combined.setdefault(name, set())
877
            p.update(map(weave.idx_to_name, weave._parents[idx]))
878
    return combined
879
880
1081 by Martin Pool
- if weave tool is invoked with no arguments, show help
881
def weave_toc(w):
882
    """Show the weave's table-of-contents"""
1083 by Martin Pool
- add space to store revision-id in weave files
883
    print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
884
    for i in (6, 50, 10, 10):
870 by Martin Pool
- better weave info display
885
        print '-' * i,
886
    print
946 by Martin Pool
- weave info only shows the weave headers, doesn't extract every version:
887
    for i in range(w.numversions()):
0.1.91 by Martin Pool
Update Weave.check
888
        sha1 = w._sha1s[i]
1083 by Martin Pool
- add space to store revision-id in weave files
889
        name = w._names[i]
890
        parent_str = ' '.join(map(str, w._parents[i]))
891
        print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
0.1.88 by Martin Pool
Add weave info command.
892
869 by Martin Pool
- more weave.py command line options
893
894
1393.1.4 by Martin Pool
- weave tool now finds bzrlib if it's not on the default path
895
def weave_stats(weave_file, pb):
947 by Martin Pool
- new 'weave stats' command
896
    from bzrlib.weavefile import read_weave
897
898
    wf = file(weave_file, 'rb')
899
    w = read_weave(wf)
900
    # FIXME: doesn't work on pipes
901
    weave_size = wf.tell()
902
903
    total = 0
904
    vers = len(w)
905
    for i in range(vers):
906
        pb.update('checking sizes', i, vers)
1393.1.24 by Martin Pool
- slight speedup for weave stats
907
        for origin, lineno, line in w._extract([i]):
947 by Martin Pool
- new 'weave stats' command
908
            total += len(line)
909
910
    pb.clear()
911
912
    print 'versions          %9d' % vers
913
    print 'weave file        %9d bytes' % weave_size
914
    print 'total contents    %9d bytes' % total
915
    print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
916
    if vers:
917
        avg = total/vers
918
        print 'average size      %9d bytes' % avg
919
        print 'relative size     %9.2fx' % (float(weave_size) / float(avg))
947 by Martin Pool
- new 'weave stats' command
920
921
869 by Martin Pool
- more weave.py command line options
922
def usage():
871 by Martin Pool
- add command for merge-based weave
923
    print """bzr weave tool
924
925
Experimental tool for weave algorithm.
926
869 by Martin Pool
- more weave.py command line options
927
usage:
928
    weave init WEAVEFILE
929
        Create an empty weave file
930
    weave get WEAVEFILE VERSION
931
        Write out specified version.
932
    weave check WEAVEFILE
933
        Check consistency of all versions.
1081 by Martin Pool
- if weave tool is invoked with no arguments, show help
934
    weave toc WEAVEFILE
869 by Martin Pool
- more weave.py command line options
935
        Display table of contents.
1084 by Martin Pool
- weave add command needs to take a symbolic name too
936
    weave add WEAVEFILE NAME [BASE...] < NEWTEXT
869 by Martin Pool
- more weave.py command line options
937
        Add NEWTEXT, with specified parent versions.
938
    weave annotate WEAVEFILE VERSION
939
        Display origin of each line.
940
    weave mash WEAVEFILE VERSION...
941
        Display composite of all selected versions.
942
    weave merge WEAVEFILE VERSION1 VERSION2 > OUT
943
        Auto-merge two versions and display conflicts.
1329 by Martin Pool
- add diff command to weave utility
944
    weave diff WEAVEFILE VERSION1 VERSION2 
945
        Show differences between two versions.
871 by Martin Pool
- add command for merge-based weave
946
947
example:
948
949
    % weave init foo.weave
950
    % vi foo.txt
1084 by Martin Pool
- weave add command needs to take a symbolic name too
951
    % weave add foo.weave ver0 < foo.txt
871 by Martin Pool
- add command for merge-based weave
952
    added version 0
953
954
    (create updated version)
955
    % vi foo.txt
956
    % weave get foo.weave 0 | diff -u - foo.txt
1084 by Martin Pool
- weave add command needs to take a symbolic name too
957
    % weave add foo.weave ver1 0 < foo.txt
871 by Martin Pool
- add command for merge-based weave
958
    added version 1
959
960
    % weave get foo.weave 0 > foo.txt       (create forked version)
961
    % vi foo.txt
1084 by Martin Pool
- weave add command needs to take a symbolic name too
962
    % weave add foo.weave ver2 0 < foo.txt
871 by Martin Pool
- add command for merge-based weave
963
    added version 2
964
965
    % weave merge foo.weave 1 2 > foo.txt   (merge them)
966
    % vi foo.txt                            (resolve conflicts)
1084 by Martin Pool
- weave add command needs to take a symbolic name too
967
    % weave add foo.weave merged 1 2 < foo.txt     (commit merged version)     
871 by Martin Pool
- add command for merge-based weave
968
    
869 by Martin Pool
- more weave.py command line options
969
"""
0.1.88 by Martin Pool
Add weave info command.
970
    
971
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
972
973
def main(argv):
974
    import sys
975
    import os
1393.1.4 by Martin Pool
- weave tool now finds bzrlib if it's not on the default path
976
    try:
977
        import bzrlib
978
    except ImportError:
979
        # in case we're run directly from the subdirectory
980
        sys.path.append('..')
981
        import bzrlib
1336 by Martin Pool
- tidy up import
982
    from bzrlib.weavefile import write_weave, read_weave
894 by Martin Pool
- small optimization for weave extract
983
    from bzrlib.progress import ProgressBar
984
1078 by Martin Pool
- use psyco for weave if possible
985
    try:
986
        import psyco
987
        psyco.full()
988
    except ImportError:
989
        pass
894 by Martin Pool
- small optimization for weave extract
990
1081 by Martin Pool
- if weave tool is invoked with no arguments, show help
991
    if len(argv) < 2:
992
        usage()
993
        return 0
994
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
995
    cmd = argv[1]
869 by Martin Pool
- more weave.py command line options
996
997
    def readit():
998
        return read_weave(file(argv[2], 'rb'))
999
    
1000
    if cmd == 'help':
1001
        usage()
1002
    elif cmd == 'add':
1003
        w = readit()
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
1004
        # at the moment, based on everything in the file
1084 by Martin Pool
- weave add command needs to take a symbolic name too
1005
        name = argv[3]
1006
        parents = map(int, argv[4:])
0.1.72 by Martin Pool
Go back to weave lines normally having newlines at the end.
1007
        lines = sys.stdin.readlines()
1084 by Martin Pool
- weave add command needs to take a symbolic name too
1008
        ver = w.add(name, parents, lines)
869 by Martin Pool
- more weave.py command line options
1009
        write_weave(w, file(argv[2], 'wb'))
1084 by Martin Pool
- weave add command needs to take a symbolic name too
1010
        print 'added version %r %d' % (name, ver)
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
1011
    elif cmd == 'init':
1012
        fn = argv[2]
1013
        if os.path.exists(fn):
1014
            raise IOError("file exists")
1015
        w = Weave()
869 by Martin Pool
- more weave.py command line options
1016
        write_weave(w, file(fn, 'wb'))
1017
    elif cmd == 'get': # get one version
1018
        w = readit()
0.1.94 by Martin Pool
Fix get_iter call
1019
        sys.stdout.writelines(w.get_iter(int(argv[3])))
869 by Martin Pool
- more weave.py command line options
1020
        
1021
    elif cmd == 'mash': # get composite
1022
        w = readit()
1023
        sys.stdout.writelines(w.mash_iter(map(int, argv[3:])))
1024
1329 by Martin Pool
- add diff command to weave utility
1025
    elif cmd == 'diff':
1026
        from difflib import unified_diff
1027
        w = readit()
1028
        fn = argv[2]
1029
        v1, v2 = map(int, argv[3:5])
1030
        lines1 = w.get(v1)
1031
        lines2 = w.get(v2)
1032
        diff_gen = unified_diff(lines1, lines2,
1033
                                '%s version %d' % (fn, v1),
1034
                                '%s version %d' % (fn, v2))
1035
        sys.stdout.writelines(diff_gen)
1036
            
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
1037
    elif cmd == 'annotate':
869 by Martin Pool
- more weave.py command line options
1038
        w = readit()
0.1.72 by Martin Pool
Go back to weave lines normally having newlines at the end.
1039
        # newline is added to all lines regardless; too hard to get
1040
        # reasonable formatting otherwise
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
1041
        lasto = None
1042
        for origin, text in w.annotate(int(argv[3])):
0.1.72 by Martin Pool
Go back to weave lines normally having newlines at the end.
1043
            text = text.rstrip('\r\n')
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
1044
            if origin == lasto:
1045
                print '      | %s' % (text)
1046
            else:
1047
                print '%5d | %s' % (origin, text)
1048
                lasto = origin
871 by Martin Pool
- add command for merge-based weave
1049
                
1081 by Martin Pool
- if weave tool is invoked with no arguments, show help
1050
    elif cmd == 'toc':
1051
        weave_toc(readit())
947 by Martin Pool
- new 'weave stats' command
1052
1053
    elif cmd == 'stats':
1393.1.4 by Martin Pool
- weave tool now finds bzrlib if it's not on the default path
1054
        weave_stats(argv[2], ProgressBar())
871 by Martin Pool
- add command for merge-based weave
1055
        
0.1.91 by Martin Pool
Update Weave.check
1056
    elif cmd == 'check':
869 by Martin Pool
- more weave.py command line options
1057
        w = readit()
894 by Martin Pool
- small optimization for weave extract
1058
        pb = ProgressBar()
1059
        w.check(pb)
1060
        pb.clear()
938 by Martin Pool
- various optimizations to weave add code
1061
        print '%d versions ok' % w.numversions()
871 by Martin Pool
- add command for merge-based weave
1062
892 by Martin Pool
- weave stores only direct parents, and calculates and memoizes expansion as needed
1063
    elif cmd == 'inclusions':
1064
        w = readit()
1065
        print ' '.join(map(str, w.inclusions([int(argv[3])])))
1066
1067
    elif cmd == 'parents':
1068
        w = readit()
944 by Martin Pool
- refactor member names in Weave code
1069
        print ' '.join(map(str, w._parents[int(argv[3])]))
892 by Martin Pool
- weave stores only direct parents, and calculates and memoizes expansion as needed
1070
918 by Martin Pool
- start doing new weave-merge algorithm
1071
    elif cmd == 'plan-merge':
1072
        w = readit()
1073
        for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
919 by Martin Pool
- more development of weave-merge
1074
            if line:
1075
                print '%14s | %s' % (state, line),
918 by Martin Pool
- start doing new weave-merge algorithm
1076
871 by Martin Pool
- add command for merge-based weave
1077
    elif cmd == 'merge':
919 by Martin Pool
- more development of weave-merge
1078
        w = readit()
1079
        p = w.plan_merge(int(argv[3]), int(argv[4]))
1080
        sys.stdout.writelines(w.weave_merge(p))
1081
            
1082
    elif cmd == 'mash-merge':
871 by Martin Pool
- add command for merge-based weave
1083
        if len(argv) != 5:
1084
            usage()
1085
            return 1
1086
1087
        w = readit()
1088
        v1, v2 = map(int, argv[3:5])
1089
1090
        basis = w.inclusions([v1]).intersection(w.inclusions([v2]))
1091
1092
        base_lines = list(w.mash_iter(basis))
1093
        a_lines = list(w.get(v1))
1094
        b_lines = list(w.get(v2))
1095
1096
        from bzrlib.merge3 import Merge3
1097
        m3 = Merge3(base_lines, a_lines, b_lines)
1098
1099
        name_a = 'version %d' % v1
1100
        name_b = 'version %d' % v2
1101
        sys.stdout.writelines(m3.merge_lines(name_a=name_a, name_b=name_b))
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
1102
    else:
1103
        raise ValueError('unknown command %r' % cmd)
1104
    
1105
1076 by Martin Pool
- add code to run weave utility under profiler
1106
1107
def profile_main(argv): 
1108
    import tempfile, hotshot, hotshot.stats
1109
1110
    prof_f = tempfile.NamedTemporaryFile()
1111
1112
    prof = hotshot.Profile(prof_f.name)
1113
1114
    ret = prof.runcall(main, argv)
1115
    prof.close()
1116
1117
    stats = hotshot.stats.load(prof_f.name)
1118
    #stats.strip_dirs()
1079 by Martin Pool
- weavefile can just use lists for read-in ancestry, not frozensets
1119
    stats.sort_stats('cumulative')
1076 by Martin Pool
- add code to run weave utility under profiler
1120
    ## XXX: Might like to write to stderr or the trace file instead but
1121
    ## print_stats seems hardcoded to stdout
1122
    stats.print_stats(20)
1123
            
1124
    return ret
1125
1126
0.1.62 by Martin Pool
Lame command-line client for reading and writing weaves.
1127
if __name__ == '__main__':
1128
    import sys
1081 by Martin Pool
- if weave tool is invoked with no arguments, show help
1129
    if '--profile' in sys.argv:
1078 by Martin Pool
- use psyco for weave if possible
1130
        args = sys.argv[:]
1081 by Martin Pool
- if weave tool is invoked with no arguments, show help
1131
        args.remove('--profile')
1078 by Martin Pool
- use psyco for weave if possible
1132
        sys.exit(profile_main(args))
1133
    else:
1134
        sys.exit(main(sys.argv))
1076 by Martin Pool
- add code to run weave utility under profiler
1135