~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: Martin Pool
  • Date: 2005-08-18 05:22:01 UTC
  • Revision ID: mbp@sourcefrog.net-20050818052201-54c5e07b377e2af8
- don't store redundant version number at end of insert blocks

This introduces a new weavefile version (v4); the code can't read old ones.

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
49
 
 
50
 
 
51
 
 
 
48
# with all this and simplification of add code, 33s 
52
49
 
53
50
 
54
51
# TODO: Perhaps have copy method for Weave instances?
62
59
# binaries, perhaps by naively splitting on \n or perhaps using
63
60
# something like a rolling checksum.
64
61
 
 
62
# TODO: Track version names as well as indexes. 
 
63
 
65
64
# TODO: End marker for each version so we can stop reading?
66
65
 
67
66
# TODO: Check that no insertion occurs inside a deletion that was
76
75
# description of which revisions include it.  Nice for checking all
77
76
# shas in parallel.
78
77
 
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
90
78
 
91
79
 
92
80
 
174
162
        each version; the parent's parents are implied.
175
163
 
176
164
    _sha1s
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.
 
165
        List of hex SHA-1 of each version, or None if not recorded.
184
166
    """
185
167
 
186
 
    __slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map']
 
168
    __slots__ = ['_weave', '_parents', '_sha1s']
187
169
    
188
170
    def __init__(self):
189
171
        self._weave = []
190
172
        self._parents = []
191
173
        self._sha1s = []
192
 
        self._names = []
193
 
        self._name_map = {}
194
174
 
195
175
 
196
176
    def __eq__(self, other):
197
177
        if not isinstance(other, Weave):
198
178
            return False
199
179
        return self._parents == other._parents \
200
 
               and self._weave == other._weave \
201
 
               and self._sha1s == other._sha1s 
 
180
               and self._weave == other._weave
 
181
    
202
182
 
203
 
    
204
183
    def __ne__(self, other):
205
184
        return not self.__eq__(other)
206
185
 
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
 
 
214
186
        
215
 
    def add(self, name, parents, text):
 
187
    def add(self, parents, text):
216
188
        """Add a single text on top of the weave.
217
189
  
218
190
        Returns the index number of the newly added version.
219
191
 
220
 
        name
221
 
            Symbolic name for this version.
222
 
            (Typically the revision-id of the revision that added it.)
223
 
 
224
192
        parents
225
193
            List or set of direct parent version numbers.
226
194
            
227
195
        text
228
196
            Sequence of lines to be added in the new version."""
229
197
 
230
 
        assert isinstance(name, basestring)
231
 
        if name in self._name_map:
232
 
            raise WeaveError("name %r already present in weave" % name)
233
 
        
234
198
        self._check_versions(parents)
235
199
        ## self._check_lines(text)
236
200
        new_version = len(self._parents)
237
201
 
 
202
        import sha
238
203
        s = sha.new()
239
204
        map(s.update, text)
240
205
        sha1 = s.hexdigest()
241
206
        del s
242
207
 
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
        # if we abort after here the weave will be corrupt
 
209
        self._parents.append(frozenset(parents))
246
210
        self._sha1s.append(sha1)
247
 
        self._names.append(name)
248
 
        self._name_map[name] = new_version
249
211
 
250
212
            
251
213
        if not parents:
548
510
 
549
511
        # try extracting all versions; this is a bit slow and parallel
550
512
        # extraction could be used
 
513
        import sha
551
514
        nv = self.numversions()
552
515
        for version in range(nv):
553
516
            if progress_bar:
709
672
 
710
673
 
711
674
 
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):
 
675
def weave_info(w):
 
676
    """Show some text information about the weave."""
 
677
    print '%6s %40s %20s' % ('ver', 'sha1', 'parents')
 
678
    for i in (6, 40, 20):
716
679
        print '-' * i,
717
680
    print
718
681
    for i in range(w.numversions()):
719
682
        sha1 = w._sha1s[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)
 
683
        print '%6d %40s %s' % (i, sha1, ' '.join(map(str, w._parents[i])))
723
684
 
724
685
 
725
686
 
765
726
        Write out specified version.
766
727
    weave check WEAVEFILE
767
728
        Check consistency of all versions.
768
 
    weave toc WEAVEFILE
 
729
    weave info WEAVEFILE
769
730
        Display table of contents.
770
 
    weave add WEAVEFILE NAME [BASE...] < NEWTEXT
 
731
    weave add WEAVEFILE [BASE...] < NEWTEXT
771
732
        Add NEWTEXT, with specified parent versions.
772
733
    weave annotate WEAVEFILE VERSION
773
734
        Display origin of each line.
780
741
 
781
742
    % weave init foo.weave
782
743
    % vi foo.txt
783
 
    % weave add foo.weave ver0 < foo.txt
 
744
    % weave add foo.weave < foo.txt
784
745
    added version 0
785
746
 
786
747
    (create updated version)
787
748
    % vi foo.txt
788
749
    % weave get foo.weave 0 | diff -u - foo.txt
789
 
    % weave add foo.weave ver1 0 < foo.txt
 
750
    % weave add foo.weave 0 < foo.txt
790
751
    added version 1
791
752
 
792
753
    % weave get foo.weave 0 > foo.txt       (create forked version)
793
754
    % vi foo.txt
794
 
    % weave add foo.weave ver2 0 < foo.txt
 
755
    % weave add foo.weave 0 < foo.txt
795
756
    added version 2
796
757
 
797
758
    % weave merge foo.weave 1 2 > foo.txt   (merge them)
798
759
    % vi foo.txt                            (resolve conflicts)
799
 
    % weave add foo.weave merged 1 2 < foo.txt     (commit merged version)     
 
760
    % weave add foo.weave 1 2 < foo.txt     (commit merged version)     
800
761
    
801
762
"""
802
763
    
808
769
    from weavefile import write_weave, read_weave
809
770
    from bzrlib.progress import ProgressBar
810
771
 
811
 
    try:
812
 
        import psyco
813
 
        psyco.full()
814
 
    except ImportError:
815
 
        pass
816
 
 
817
 
    if len(argv) < 2:
818
 
        usage()
819
 
        return 0
 
772
    #import psyco
 
773
    #psyco.full()
820
774
 
821
775
    cmd = argv[1]
822
776
 
828
782
    elif cmd == 'add':
829
783
        w = readit()
830
784
        # at the moment, based on everything in the file
831
 
        name = argv[3]
832
 
        parents = map(int, argv[4:])
 
785
        parents = map(int, argv[3:])
833
786
        lines = sys.stdin.readlines()
834
 
        ver = w.add(name, parents, lines)
 
787
        ver = w.add(parents, lines)
835
788
        write_weave(w, file(argv[2], 'wb'))
836
 
        print 'added version %r %d' % (name, ver)
 
789
        print 'added version %d' % ver
837
790
    elif cmd == 'init':
838
791
        fn = argv[2]
839
792
        if os.path.exists(fn):
861
814
                print '%5d | %s' % (origin, text)
862
815
                lasto = origin
863
816
                
864
 
    elif cmd == 'toc':
865
 
        weave_toc(readit())
 
817
    elif cmd == 'info':
 
818
        weave_info(readit())
866
819
 
867
820
    elif cmd == 'stats':
868
821
        weave_stats(argv[2])
917
870
        raise ValueError('unknown command %r' % cmd)
918
871
    
919
872
 
920
 
 
921
 
def profile_main(argv): 
922
 
    import tempfile, hotshot, hotshot.stats
923
 
 
924
 
    prof_f = tempfile.NamedTemporaryFile()
925
 
 
926
 
    prof = hotshot.Profile(prof_f.name)
927
 
 
928
 
    ret = prof.runcall(main, argv)
929
 
    prof.close()
930
 
 
931
 
    stats = hotshot.stats.load(prof_f.name)
932
 
    #stats.strip_dirs()
933
 
    stats.sort_stats('cumulative')
934
 
    ## XXX: Might like to write to stderr or the trace file instead but
935
 
    ## print_stats seems hardcoded to stdout
936
 
    stats.print_stats(20)
937
 
            
938
 
    return ret
939
 
 
940
 
 
941
873
if __name__ == '__main__':
942
874
    import sys
943
 
    if '--profile' in sys.argv:
944
 
        args = sys.argv[:]
945
 
        args.remove('--profile')
946
 
        sys.exit(profile_main(args))
947
 
    else:
948
 
        sys.exit(main(sys.argv))
949
 
 
 
875
    sys.exit(main(sys.argv))