/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: Martin Pool
  • Date: 2005-08-18 07:51:58 UTC
  • Revision ID: mbp@sourcefrog.net-20050818075157-5f69075fa843d558
- add space to store revision-id in weave files

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
 
46
46
# with delta folded in and mutation of the list, 36.13s
47
47
 
48
 
# with all this and simplification of add code, 33s 
 
48
# with all this and simplification of add code, 33s
 
49
 
 
50
 
 
51
 
49
52
 
50
53
 
51
54
# TODO: Perhaps have copy method for Weave instances?
59
62
# binaries, perhaps by naively splitting on \n or perhaps using
60
63
# something like a rolling checksum.
61
64
 
62
 
# TODO: Track version names as well as indexes. 
63
 
 
64
65
# TODO: End marker for each version so we can stop reading?
65
66
 
66
67
# TODO: Check that no insertion occurs inside a deletion that was
75
76
# description of which revisions include it.  Nice for checking all
76
77
# shas in parallel.
77
78
 
 
79
# TODO: Using a single _extract routine and then processing the output
 
80
# is probably inefficient.  It's simple enough that we can afford to
 
81
# have slight specializations for different ways its used: annotate,
 
82
# basis for add, get, etc.
 
83
 
 
84
# TODO: Perhaps the API should work only in names to hide the integer
 
85
# indexes from the user?
 
86
 
 
87
 
 
88
 
 
89
import sha
78
90
 
79
91
 
80
92
 
101
113
 
102
114
    * a nonnegative index number.
103
115
 
104
 
    * a version-id string.
 
116
    * a version-id string. (not implemented yet)
105
117
 
106
118
    Typically the index number will be valid only inside this weave and
107
119
    the version-id is used to reference it in the larger world.
118
130
    The instruction can be '{' or '}' for an insertion block, and '['
119
131
    and ']' for a deletion block respectively.  The version is the
120
132
    integer version index.  There is no replace operator, only deletes
121
 
    and inserts.
 
133
    and inserts.  For '}', the end of an insertion, there is no
 
134
    version parameter because it always closes the most recently
 
135
    opened insertion.
122
136
 
123
137
    Constraints/notes:
124
138
 
160
174
        each version; the parent's parents are implied.
161
175
 
162
176
    _sha1s
163
 
        List of hex SHA-1 of each version, or None if not recorded.
 
177
        List of hex SHA-1 of each version.
 
178
 
 
179
    _names
 
180
        List of symbolic names for each version.  Each should be unique.
 
181
 
 
182
    _name_map
 
183
        For each name, the version number.
164
184
    """
165
185
 
166
 
    __slots__ = ['_weave', '_parents', '_sha1s']
 
186
    __slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map']
167
187
    
168
188
    def __init__(self):
169
189
        self._weave = []
170
190
        self._parents = []
171
191
        self._sha1s = []
 
192
        self._names = []
 
193
        self._name_map = {}
172
194
 
173
195
 
174
196
    def __eq__(self, other):
175
197
        if not isinstance(other, Weave):
176
198
            return False
177
199
        return self._parents == other._parents \
178
 
               and self._weave == other._weave
 
200
               and self._weave == other._weave \
 
201
               and self._sha1s == other._sha1s 
 
202
 
179
203
    
180
 
 
181
204
    def __ne__(self, other):
182
205
        return not self.__eq__(other)
183
206
 
 
207
 
 
208
    def lookup(self, name):
 
209
        try:
 
210
            return self._name_map[name]
 
211
        except KeyError:
 
212
            raise WeaveError("name %s not present in weave" % name)
 
213
 
184
214
        
185
 
    def add(self, parents, text):
 
215
    def add(self, name, parents, text):
186
216
        """Add a single text on top of the weave.
187
217
  
188
218
        Returns the index number of the newly added version.
189
219
 
 
220
        name
 
221
            Symbolic name for this version.
 
222
            (Typically the revision-id of the revision that added it.)
 
223
 
190
224
        parents
191
225
            List or set of direct parent version numbers.
192
226
            
193
227
        text
194
228
            Sequence of lines to be added in the new version."""
195
229
 
 
230
        assert isinstance(name, basestring)
 
231
        if name in self._name_map:
 
232
            raise WeaveError("name %r already present in weave" % name)
 
233
        
196
234
        self._check_versions(parents)
197
235
        ## self._check_lines(text)
198
236
        new_version = len(self._parents)
199
237
 
200
 
        import sha
201
238
        s = sha.new()
202
239
        map(s.update, text)
203
240
        sha1 = s.hexdigest()
204
241
        del s
205
242
 
206
 
        # if we abort after here the weave will be corrupt
207
 
        self._parents.append(frozenset(parents))
 
243
        # if we abort after here the (in-memory) weave will be corrupt because only
 
244
        # some fields are updated
 
245
        self._parents.append(parents[:])
208
246
        self._sha1s.append(sha1)
 
247
        self._names.append(name)
 
248
        self._name_map[name] = new_version
209
249
 
210
250
            
211
251
        if not parents:
216
256
            if text:
217
257
                self._weave.append(('{', new_version))
218
258
                self._weave.extend(text)
219
 
                self._weave.append(('}', new_version))
 
259
                self._weave.append(('}', None))
220
260
        
221
261
            return new_version
222
262
 
238
278
            basis_lineno.append(lineno)
239
279
            basis_lines.append(line)
240
280
 
241
 
        # another small special case: a merge, producing the same text as auto-merge
 
281
        # another small special case: a merge, producing the same text
 
282
        # as auto-merge
242
283
        if text == basis_lines:
243
284
            return new_version            
244
285
 
287
328
                # we don't destroy ourselves
288
329
                i = i2 + offset
289
330
                self._weave[i:i] = ([('{', new_version)] 
290
 
                                + text[j1:j2] 
291
 
                                + [('}', new_version)])
 
331
                                    + text[j1:j2] 
 
332
                                    + [('}', None)])
292
333
                offset += 2 + (j2 - j1)
293
334
 
294
335
        return new_version
384
425
                if c == '{':
385
426
                    istack.append(v)
386
427
                elif c == '}':
387
 
                    oldv = istack.pop()
 
428
                    istack.pop()
388
429
                elif c == '[':
389
430
                    assert v not in dset
390
431
                    dset.add(v)
431
472
                    assert v not in istack
432
473
                    istack.append(v)
433
474
                elif c == '}':
434
 
                    oldv = istack.pop()
435
 
                    assert oldv == v
 
475
                    istack.pop()
436
476
                elif c == '[':
437
477
                    if v in included:
438
478
                        assert v not in dset
508
548
 
509
549
        # try extracting all versions; this is a bit slow and parallel
510
550
        # extraction could be used
511
 
        import sha
512
551
        nv = self.numversions()
513
552
        for version in range(nv):
514
553
            if progress_bar:
670
709
 
671
710
 
672
711
 
673
 
def weave_info(w):
674
 
    """Show some text information about the weave."""
675
 
    print '%6s %40s %20s' % ('ver', 'sha1', 'parents')
676
 
    for i in (6, 40, 20):
 
712
def weave_toc(w):
 
713
    """Show the weave's table-of-contents"""
 
714
    print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
 
715
    for i in (6, 50, 10, 10):
677
716
        print '-' * i,
678
717
    print
679
718
    for i in range(w.numversions()):
680
719
        sha1 = w._sha1s[i]
681
 
        print '%6d %40s %s' % (i, sha1, ' '.join(map(str, w._parents[i])))
 
720
        name = w._names[i]
 
721
        parent_str = ' '.join(map(str, w._parents[i]))
 
722
        print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
682
723
 
683
724
 
684
725
 
706
747
    print 'weave file        %9d bytes' % weave_size
707
748
    print 'total contents    %9d bytes' % total
708
749
    print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
709
 
 
 
750
    if vers:
 
751
        avg = total/vers
 
752
        print 'average size      %9d bytes' % avg
 
753
        print 'relative size     %9.2fx' % (float(weave_size) / float(avg))
710
754
 
711
755
 
712
756
def usage():
721
765
        Write out specified version.
722
766
    weave check WEAVEFILE
723
767
        Check consistency of all versions.
724
 
    weave info WEAVEFILE
 
768
    weave toc WEAVEFILE
725
769
        Display table of contents.
726
770
    weave add WEAVEFILE [BASE...] < NEWTEXT
727
771
        Add NEWTEXT, with specified parent versions.
764
808
    from weavefile import write_weave, read_weave
765
809
    from bzrlib.progress import ProgressBar
766
810
 
767
 
    #import psyco
768
 
    #psyco.full()
 
811
    try:
 
812
        import psyco
 
813
        psyco.full()
 
814
    except ImportError:
 
815
        pass
 
816
 
 
817
    if len(argv) < 2:
 
818
        usage()
 
819
        return 0
769
820
 
770
821
    cmd = argv[1]
771
822
 
809
860
                print '%5d | %s' % (origin, text)
810
861
                lasto = origin
811
862
                
812
 
    elif cmd == 'info':
813
 
        weave_info(readit())
 
863
    elif cmd == 'toc':
 
864
        weave_toc(readit())
814
865
 
815
866
    elif cmd == 'stats':
816
867
        weave_stats(argv[2])
865
916
        raise ValueError('unknown command %r' % cmd)
866
917
    
867
918
 
 
919
 
 
920
def profile_main(argv): 
 
921
    import tempfile, hotshot, hotshot.stats
 
922
 
 
923
    prof_f = tempfile.NamedTemporaryFile()
 
924
 
 
925
    prof = hotshot.Profile(prof_f.name)
 
926
 
 
927
    ret = prof.runcall(main, argv)
 
928
    prof.close()
 
929
 
 
930
    stats = hotshot.stats.load(prof_f.name)
 
931
    #stats.strip_dirs()
 
932
    stats.sort_stats('cumulative')
 
933
    ## XXX: Might like to write to stderr or the trace file instead but
 
934
    ## print_stats seems hardcoded to stdout
 
935
    stats.print_stats(20)
 
936
            
 
937
    return ret
 
938
 
 
939
 
868
940
if __name__ == '__main__':
869
941
    import sys
870
 
    sys.exit(main(sys.argv))
 
942
    if '--profile' in sys.argv:
 
943
        args = sys.argv[:]
 
944
        args.remove('--profile')
 
945
        sys.exit(profile_main(args))
 
946
    else:
 
947
        sys.exit(main(sys.argv))
 
948