~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: aaron.bentley at utoronto
  • Date: 2005-08-21 00:08:08 UTC
  • mto: (1092.1.41) (1185.3.4)
  • mto: This revision was merged to the branch mainline in revision 1110.
  • Revision ID: aaron.bentley@utoronto.ca-20050821000808-2a0e6ef95b1bca59
Changed copy_multi to permit failure and return a tuple, tested missing required revisions

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
 
113
101
 
114
102
    * a nonnegative index number.
115
103
 
116
 
    * a version-id string. (not implemented yet)
 
104
    * a version-id string.
117
105
 
118
106
    Typically the index number will be valid only inside this weave and
119
107
    the version-id is used to reference it in the larger world.
130
118
    The instruction can be '{' or '}' for an insertion block, and '['
131
119
    and ']' for a deletion block respectively.  The version is the
132
120
    integer version index.  There is no replace operator, only deletes
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.
 
121
    and inserts.
136
122
 
137
123
    Constraints/notes:
138
124
 
174
160
        each version; the parent's parents are implied.
175
161
 
176
162
    _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.
 
163
        List of hex SHA-1 of each version, or None if not recorded.
184
164
    """
185
165
 
186
 
    __slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map']
 
166
    __slots__ = ['_weave', '_parents', '_sha1s']
187
167
    
188
168
    def __init__(self):
189
169
        self._weave = []
190
170
        self._parents = []
191
171
        self._sha1s = []
192
 
        self._names = []
193
 
        self._name_map = {}
194
172
 
195
173
 
196
174
    def __eq__(self, other):
197
175
        if not isinstance(other, Weave):
198
176
            return False
199
177
        return self._parents == other._parents \
200
 
               and self._weave == other._weave \
201
 
               and self._sha1s == other._sha1s 
 
178
               and self._weave == other._weave
 
179
    
202
180
 
203
 
    
204
181
    def __ne__(self, other):
205
182
        return not self.__eq__(other)
206
183
 
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
184
        
215
 
    def add(self, name, parents, text):
 
185
    def add(self, parents, text):
216
186
        """Add a single text on top of the weave.
217
187
  
218
188
        Returns the index number of the newly added version.
219
189
 
220
 
        name
221
 
            Symbolic name for this version.
222
 
            (Typically the revision-id of the revision that added it.)
223
 
 
224
190
        parents
225
191
            List or set of direct parent version numbers.
226
192
            
227
193
        text
228
194
            Sequence of lines to be added in the new version."""
229
195
 
230
 
        assert isinstance(name, basestring)
231
 
        if name in self._name_map:
232
 
            raise WeaveError("name %r already present in weave" % name)
233
 
        
234
196
        self._check_versions(parents)
235
197
        ## self._check_lines(text)
236
198
        new_version = len(self._parents)
237
199
 
 
200
        import sha
238
201
        s = sha.new()
239
202
        map(s.update, text)
240
203
        sha1 = s.hexdigest()
241
204
        del s
242
205
 
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[:])
 
206
        # if we abort after here the weave will be corrupt
 
207
        self._parents.append(frozenset(parents))
246
208
        self._sha1s.append(sha1)
247
 
        self._names.append(name)
248
 
        self._name_map[name] = new_version
249
209
 
250
210
            
251
211
        if not parents:
256
216
            if text:
257
217
                self._weave.append(('{', new_version))
258
218
                self._weave.extend(text)
259
 
                self._weave.append(('}', None))
 
219
                self._weave.append(('}', new_version))
260
220
        
261
221
            return new_version
262
222
 
328
288
                # we don't destroy ourselves
329
289
                i = i2 + offset
330
290
                self._weave[i:i] = ([('{', new_version)] 
331
 
                                    + text[j1:j2] 
332
 
                                    + [('}', None)])
 
291
                                + text[j1:j2] 
 
292
                                + [('}', new_version)])
333
293
                offset += 2 + (j2 - j1)
334
294
 
335
295
        return new_version
425
385
                if c == '{':
426
386
                    istack.append(v)
427
387
                elif c == '}':
428
 
                    istack.pop()
 
388
                    oldv = istack.pop()
429
389
                elif c == '[':
430
390
                    assert v not in dset
431
391
                    dset.add(v)
472
432
                    assert v not in istack
473
433
                    istack.append(v)
474
434
                elif c == '}':
475
 
                    istack.pop()
 
435
                    oldv = istack.pop()
 
436
                    assert oldv == v
476
437
                elif c == '[':
477
438
                    if v in included:
478
439
                        assert v not in dset
548
509
 
549
510
        # try extracting all versions; this is a bit slow and parallel
550
511
        # extraction could be used
 
512
        import sha
551
513
        nv = self.numversions()
552
514
        for version in range(nv):
553
515
            if progress_bar:
709
671
 
710
672
 
711
673
 
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):
 
674
def weave_info(w):
 
675
    """Show some text information about the weave."""
 
676
    print '%6s %40s %20s' % ('ver', 'sha1', 'parents')
 
677
    for i in (6, 40, 20):
716
678
        print '-' * i,
717
679
    print
718
680
    for i in range(w.numversions()):
719
681
        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)
 
682
        print '%6d %40s %s' % (i, sha1, ' '.join(map(str, w._parents[i])))
723
683
 
724
684
 
725
685
 
765
725
        Write out specified version.
766
726
    weave check WEAVEFILE
767
727
        Check consistency of all versions.
768
 
    weave toc WEAVEFILE
 
728
    weave info WEAVEFILE
769
729
        Display table of contents.
770
 
    weave add WEAVEFILE NAME [BASE...] < NEWTEXT
 
730
    weave add WEAVEFILE [BASE...] < NEWTEXT
771
731
        Add NEWTEXT, with specified parent versions.
772
732
    weave annotate WEAVEFILE VERSION
773
733
        Display origin of each line.
780
740
 
781
741
    % weave init foo.weave
782
742
    % vi foo.txt
783
 
    % weave add foo.weave ver0 < foo.txt
 
743
    % weave add foo.weave < foo.txt
784
744
    added version 0
785
745
 
786
746
    (create updated version)
787
747
    % vi foo.txt
788
748
    % weave get foo.weave 0 | diff -u - foo.txt
789
 
    % weave add foo.weave ver1 0 < foo.txt
 
749
    % weave add foo.weave 0 < foo.txt
790
750
    added version 1
791
751
 
792
752
    % weave get foo.weave 0 > foo.txt       (create forked version)
793
753
    % vi foo.txt
794
 
    % weave add foo.weave ver2 0 < foo.txt
 
754
    % weave add foo.weave 0 < foo.txt
795
755
    added version 2
796
756
 
797
757
    % weave merge foo.weave 1 2 > foo.txt   (merge them)
798
758
    % vi foo.txt                            (resolve conflicts)
799
 
    % weave add foo.weave merged 1 2 < foo.txt     (commit merged version)     
 
759
    % weave add foo.weave 1 2 < foo.txt     (commit merged version)     
800
760
    
801
761
"""
802
762
    
808
768
    from weavefile import write_weave, read_weave
809
769
    from bzrlib.progress import ProgressBar
810
770
 
811
 
    try:
812
 
        import psyco
813
 
        psyco.full()
814
 
    except ImportError:
815
 
        pass
816
 
 
817
 
    if len(argv) < 2:
818
 
        usage()
819
 
        return 0
 
771
    #import psyco
 
772
    #psyco.full()
820
773
 
821
774
    cmd = argv[1]
822
775
 
828
781
    elif cmd == 'add':
829
782
        w = readit()
830
783
        # at the moment, based on everything in the file
831
 
        name = argv[3]
832
 
        parents = map(int, argv[4:])
 
784
        parents = map(int, argv[3:])
833
785
        lines = sys.stdin.readlines()
834
 
        ver = w.add(name, parents, lines)
 
786
        ver = w.add(parents, lines)
835
787
        write_weave(w, file(argv[2], 'wb'))
836
 
        print 'added version %r %d' % (name, ver)
 
788
        print 'added version %d' % ver
837
789
    elif cmd == 'init':
838
790
        fn = argv[2]
839
791
        if os.path.exists(fn):
861
813
                print '%5d | %s' % (origin, text)
862
814
                lasto = origin
863
815
                
864
 
    elif cmd == 'toc':
865
 
        weave_toc(readit())
 
816
    elif cmd == 'info':
 
817
        weave_info(readit())
866
818
 
867
819
    elif cmd == 'stats':
868
820
        weave_stats(argv[2])
917
869
        raise ValueError('unknown command %r' % cmd)
918
870
    
919
871
 
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
872
if __name__ == '__main__':
942
873
    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
 
 
 
874
    sys.exit(main(sys.argv))