46
46
# with delta folded in and mutation of the list, 36.13s
48
# with all this and simplification of add code, 33s
48
# with all this and simplification of add code, 33s
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.
62
# TODO: Track version names as well as indexes.
65
64
# TODO: End marker for each version so we can stop reading?
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.
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.
84
# TODO: Perhaps the API should work only in names to hide the integer
85
# indexes from the user?
174
162
each version; the parent's parents are implied.
177
List of hex SHA-1 of each version.
180
List of symbolic names for each version. Each should be unique.
183
For each name, the version number.
165
List of hex SHA-1 of each version, or None if not recorded.
186
__slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map']
168
__slots__ = ['_weave', '_parents', '_sha1s']
188
170
def __init__(self):
190
172
self._parents = []
196
176
def __eq__(self, other):
197
177
if not isinstance(other, Weave):
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
204
183
def __ne__(self, other):
205
184
return not self.__eq__(other)
208
def lookup(self, name):
210
return self._name_map[name]
212
raise WeaveError("name %s not present in weave" % name)
215
def add(self, name, parents, text):
187
def add(self, parents, text):
216
188
"""Add a single text on top of the weave.
218
190
Returns the index number of the newly added version.
221
Symbolic name for this version.
222
(Typically the revision-id of the revision that added it.)
225
193
List or set of direct parent version numbers.
228
196
Sequence of lines to be added in the new version."""
230
assert isinstance(name, basestring)
231
if name in self._name_map:
232
raise WeaveError("name %r already present in weave" % name)
234
198
self._check_versions(parents)
235
199
## self._check_lines(text)
236
200
new_version = len(self._parents)
239
204
map(s.update, text)
240
205
sha1 = s.hexdigest()
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
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):
676
"""Show some text information about the weave."""
677
print '%6s %40s %20s' % ('ver', 'sha1', 'parents')
678
for i in (6, 40, 20):
718
681
for i in range(w.numversions()):
719
682
sha1 = w._sha1s[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])))
765
726
Write out specified version.
766
727
weave check WEAVEFILE
767
728
Check consistency of all versions.
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.
781
742
% weave init foo.weave
783
% weave add foo.weave ver0 < foo.txt
744
% weave add foo.weave < foo.txt
786
747
(create updated version)
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
792
753
% weave get foo.weave 0 > foo.txt (create forked version)
794
% weave add foo.weave ver2 0 < foo.txt
755
% weave add foo.weave 0 < foo.txt
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)
828
782
elif cmd == 'add':
830
784
# at the moment, based on everything in the file
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':
839
792
if os.path.exists(fn):
917
870
raise ValueError('unknown command %r' % cmd)
921
def profile_main(argv):
922
import tempfile, hotshot, hotshot.stats
924
prof_f = tempfile.NamedTemporaryFile()
926
prof = hotshot.Profile(prof_f.name)
928
ret = prof.runcall(main, argv)
931
stats = hotshot.stats.load(prof_f.name)
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)
941
873
if __name__ == '__main__':
943
if '--profile' in sys.argv:
945
args.remove('--profile')
946
sys.exit(profile_main(args))
948
sys.exit(main(sys.argv))
875
sys.exit(main(sys.argv))