69
71
from copy import copy
70
72
from cStringIO import StringIO
73
from bzrlib.lazy_import import lazy_import
74
lazy_import(globals(), """
75
from bzrlib import tsort
77
78
from bzrlib import (
81
81
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
82
82
RevisionAlreadyPresent,
83
83
RevisionNotPresent,
84
84
UnavailableRepresentation,
85
WeaveRevisionAlreadyPresent,
86
WeaveRevisionNotPresent,
86
from bzrlib.osutils import dirname, sha, sha_strings, split_lines
88
import bzrlib.errors as errors
89
from bzrlib.osutils import dirname, sha_strings, split_lines
87
90
import bzrlib.patiencediff
88
91
from bzrlib.revision import NULL_REVISION
89
92
from bzrlib.symbol_versioning import *
90
93
from bzrlib.trace import mutter
94
from bzrlib.tsort import topo_sort
91
95
from bzrlib.versionedfile import (
92
96
AbsentContentFactory,
98
101
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
699
695
# we're still spending ~1/4 of the method in isinstance though.
700
696
# so lets hard code the acceptable string classes we expect:
701
697
# 449 0 1202.9420 786.2930 bzrlib.weave:556(_extract)
702
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
698
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
704
700
# yay, down to ~1/4 the initial extract time, and our inline time
705
701
# has shrunk again, with isinstance no longer dominating.
706
702
# tweaking the stack inclusion test to use a set gives:
707
703
# 449 0 1122.8030 713.0080 bzrlib.weave:556(_extract)
708
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
704
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
710
706
# - a 5% win, or possibly just noise. However with large istacks that
711
707
# 'in' test could dominate, so I'm leaving this change in place -
712
708
# when its fast enough to consider profiling big datasets we can review.
717
713
for l in self._weave:
718
714
if l.__class__ == tuple:
968
964
super(WeaveFile, self).insert_record_stream(stream)
967
@deprecated_method(one_five)
968
def join(self, other, pb=None, msg=None, version_ids=None,
969
ignore_missing=False):
970
"""Join other into self and save."""
971
super(WeaveFile, self).join(other, pb, msg, version_ids, ignore_missing)
972
975
def _reweave(wa, wb, pb=None, msg=None):
973
976
"""Combine two weaves and return the result.
975
This works even if a revision R has different parents in
978
This works even if a revision R has different parents in
976
979
wa and wb. In the resulting weave all the parents are given.
978
This is done by just building up a new weave, maintaining ordering
981
This is done by just building up a new weave, maintaining ordering
979
982
of the versions in the two inputs. More efficient approaches
980
might be possible but it should only be necessary to do
981
this operation rarely, when a new previously ghost version is
983
might be possible but it should only be necessary to do
984
this operation rarely, when a new previously ghost version is
984
987
:param pb: An optional progress bar, indicating how far done we are
1029
1031
p = combined.setdefault(name, set())
1030
1032
p.update(map(weave._idx_to_name, weave._parents[idx]))
1031
1033
return combined
1037
"""Show the weave's table-of-contents"""
1038
print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
1039
for i in (6, 50, 10, 10):
1042
for i in range(w.num_versions()):
1045
parent_str = ' '.join(map(str, w._parents[i]))
1046
print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
1050
def weave_stats(weave_file, pb):
1051
from bzrlib.weavefile import read_weave
1053
wf = file(weave_file, 'rb')
1055
# FIXME: doesn't work on pipes
1056
weave_size = wf.tell()
1060
for i in range(vers):
1061
pb.update('checking sizes', i, vers)
1062
for origin, lineno, line in w._extract([i]):
1067
print 'versions %9d' % vers
1068
print 'weave file %9d bytes' % weave_size
1069
print 'total contents %9d bytes' % total
1070
print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
1073
print 'average size %9d bytes' % avg
1074
print 'relative size %9.2fx' % (float(weave_size) / float(avg))
1078
print """bzr weave tool
1080
Experimental tool for weave algorithm.
1083
weave init WEAVEFILE
1084
Create an empty weave file
1085
weave get WEAVEFILE VERSION
1086
Write out specified version.
1087
weave check WEAVEFILE
1088
Check consistency of all versions.
1090
Display table of contents.
1091
weave add WEAVEFILE NAME [BASE...] < NEWTEXT
1092
Add NEWTEXT, with specified parent versions.
1093
weave annotate WEAVEFILE VERSION
1094
Display origin of each line.
1095
weave merge WEAVEFILE VERSION1 VERSION2 > OUT
1096
Auto-merge two versions and display conflicts.
1097
weave diff WEAVEFILE VERSION1 VERSION2
1098
Show differences between two versions.
1102
% weave init foo.weave
1104
% weave add foo.weave ver0 < foo.txt
1107
(create updated version)
1109
% weave get foo.weave 0 | diff -u - foo.txt
1110
% weave add foo.weave ver1 0 < foo.txt
1113
% weave get foo.weave 0 > foo.txt (create forked version)
1115
% weave add foo.weave ver2 0 < foo.txt
1118
% weave merge foo.weave 1 2 > foo.txt (merge them)
1119
% vi foo.txt (resolve conflicts)
1120
% weave add foo.weave merged 1 2 < foo.txt (commit merged version)
1132
# in case we're run directly from the subdirectory
1133
sys.path.append('..')
1135
from bzrlib.weavefile import write_weave, read_weave
1136
from bzrlib.progress import ProgressBar
1151
return read_weave(file(argv[2], 'rb'))
1157
# at the moment, based on everything in the file
1159
parents = map(int, argv[4:])
1160
lines = sys.stdin.readlines()
1161
ver = w.add(name, parents, lines)
1162
write_weave(w, file(argv[2], 'wb'))
1163
print 'added version %r %d' % (name, ver)
1166
if os.path.exists(fn):
1167
raise IOError("file exists")
1169
write_weave(w, file(fn, 'wb'))
1170
elif cmd == 'get': # get one version
1172
sys.stdout.writelines(w.get_iter(int(argv[3])))
1177
v1, v2 = map(int, argv[3:5])
1180
diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
1181
'%s version %d' % (fn, v1),
1182
'%s version %d' % (fn, v2))
1183
sys.stdout.writelines(diff_gen)
1185
elif cmd == 'annotate':
1187
# newline is added to all lines regardless; too hard to get
1188
# reasonable formatting otherwise
1190
for origin, text in w.annotate(int(argv[3])):
1191
text = text.rstrip('\r\n')
1193
print ' | %s' % (text)
1195
print '%5d | %s' % (origin, text)
1201
elif cmd == 'stats':
1202
weave_stats(argv[2], ProgressBar())
1204
elif cmd == 'check':
1209
print '%d versions ok' % w.num_versions()
1211
elif cmd == 'inclusions':
1213
print ' '.join(map(str, w.inclusions([int(argv[3])])))
1215
elif cmd == 'parents':
1217
print ' '.join(map(str, w._parents[int(argv[3])]))
1219
elif cmd == 'plan-merge':
1220
# replaced by 'bzr weave-plan-merge'
1222
for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
1224
print '%14s | %s' % (state, line),
1225
elif cmd == 'merge':
1226
# replaced by 'bzr weave-merge-text'
1228
p = w.plan_merge(int(argv[3]), int(argv[4]))
1229
sys.stdout.writelines(w.weave_merge(p))
1231
raise ValueError('unknown command %r' % cmd)
1234
if __name__ == '__main__':
1236
sys.exit(main(sys.argv))