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
77
from bzrlib import (
81
80
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
82
81
RevisionAlreadyPresent,
83
82
RevisionNotPresent,
84
83
UnavailableRepresentation,
84
WeaveRevisionAlreadyPresent,
85
WeaveRevisionNotPresent,
87
import bzrlib.errors as errors
86
88
from bzrlib.osutils import dirname, sha, sha_strings, split_lines
87
89
import bzrlib.patiencediff
88
90
from bzrlib.revision import NULL_REVISION
89
91
from bzrlib.symbol_versioning import *
90
92
from bzrlib.trace import mutter
93
from bzrlib.tsort import topo_sort
91
94
from bzrlib.versionedfile import (
92
95
AbsentContentFactory,
98
100
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
699
694
# we're still spending ~1/4 of the method in isinstance though.
700
695
# so lets hard code the acceptable string classes we expect:
701
696
# 449 0 1202.9420 786.2930 bzrlib.weave:556(_extract)
702
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
697
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
704
699
# yay, down to ~1/4 the initial extract time, and our inline time
705
700
# has shrunk again, with isinstance no longer dominating.
706
701
# tweaking the stack inclusion test to use a set gives:
707
702
# 449 0 1122.8030 713.0080 bzrlib.weave:556(_extract)
708
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
703
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
710
705
# - a 5% win, or possibly just noise. However with large istacks that
711
706
# 'in' test could dominate, so I'm leaving this change in place -
712
707
# when its fast enough to consider profiling big datasets we can review.
717
712
for l in self._weave:
718
713
if l.__class__ == tuple:
968
963
super(WeaveFile, self).insert_record_stream(stream)
966
@deprecated_method(one_five)
967
def join(self, other, pb=None, msg=None, version_ids=None,
968
ignore_missing=False):
969
"""Join other into self and save."""
970
super(WeaveFile, self).join(other, pb, msg, version_ids, ignore_missing)
972
974
def _reweave(wa, wb, pb=None, msg=None):
973
975
"""Combine two weaves and return the result.
975
This works even if a revision R has different parents in
977
This works even if a revision R has different parents in
976
978
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
980
This is done by just building up a new weave, maintaining ordering
979
981
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
982
might be possible but it should only be necessary to do
983
this operation rarely, when a new previously ghost version is
984
986
:param pb: An optional progress bar, indicating how far done we are
1029
1030
p = combined.setdefault(name, set())
1030
1031
p.update(map(weave._idx_to_name, weave._parents[idx]))
1031
1032
return combined
1036
"""Show the weave's table-of-contents"""
1037
print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
1038
for i in (6, 50, 10, 10):
1041
for i in range(w.num_versions()):
1044
parent_str = ' '.join(map(str, w._parents[i]))
1045
print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
1049
def weave_stats(weave_file, pb):
1050
from bzrlib.weavefile import read_weave
1052
wf = file(weave_file, 'rb')
1054
# FIXME: doesn't work on pipes
1055
weave_size = wf.tell()
1059
for i in range(vers):
1060
pb.update('checking sizes', i, vers)
1061
for origin, lineno, line in w._extract([i]):
1066
print 'versions %9d' % vers
1067
print 'weave file %9d bytes' % weave_size
1068
print 'total contents %9d bytes' % total
1069
print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
1072
print 'average size %9d bytes' % avg
1073
print 'relative size %9.2fx' % (float(weave_size) / float(avg))
1077
print """bzr weave tool
1079
Experimental tool for weave algorithm.
1082
weave init WEAVEFILE
1083
Create an empty weave file
1084
weave get WEAVEFILE VERSION
1085
Write out specified version.
1086
weave check WEAVEFILE
1087
Check consistency of all versions.
1089
Display table of contents.
1090
weave add WEAVEFILE NAME [BASE...] < NEWTEXT
1091
Add NEWTEXT, with specified parent versions.
1092
weave annotate WEAVEFILE VERSION
1093
Display origin of each line.
1094
weave merge WEAVEFILE VERSION1 VERSION2 > OUT
1095
Auto-merge two versions and display conflicts.
1096
weave diff WEAVEFILE VERSION1 VERSION2
1097
Show differences between two versions.
1101
% weave init foo.weave
1103
% weave add foo.weave ver0 < foo.txt
1106
(create updated version)
1108
% weave get foo.weave 0 | diff -u - foo.txt
1109
% weave add foo.weave ver1 0 < foo.txt
1112
% weave get foo.weave 0 > foo.txt (create forked version)
1114
% weave add foo.weave ver2 0 < foo.txt
1117
% weave merge foo.weave 1 2 > foo.txt (merge them)
1118
% vi foo.txt (resolve conflicts)
1119
% weave add foo.weave merged 1 2 < foo.txt (commit merged version)
1131
# in case we're run directly from the subdirectory
1132
sys.path.append('..')
1134
from bzrlib.weavefile import write_weave, read_weave
1135
from bzrlib.progress import ProgressBar
1150
return read_weave(file(argv[2], 'rb'))
1156
# at the moment, based on everything in the file
1158
parents = map(int, argv[4:])
1159
lines = sys.stdin.readlines()
1160
ver = w.add(name, parents, lines)
1161
write_weave(w, file(argv[2], 'wb'))
1162
print 'added version %r %d' % (name, ver)
1165
if os.path.exists(fn):
1166
raise IOError("file exists")
1168
write_weave(w, file(fn, 'wb'))
1169
elif cmd == 'get': # get one version
1171
sys.stdout.writelines(w.get_iter(int(argv[3])))
1176
v1, v2 = map(int, argv[3:5])
1179
diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
1180
'%s version %d' % (fn, v1),
1181
'%s version %d' % (fn, v2))
1182
sys.stdout.writelines(diff_gen)
1184
elif cmd == 'annotate':
1186
# newline is added to all lines regardless; too hard to get
1187
# reasonable formatting otherwise
1189
for origin, text in w.annotate(int(argv[3])):
1190
text = text.rstrip('\r\n')
1192
print ' | %s' % (text)
1194
print '%5d | %s' % (origin, text)
1200
elif cmd == 'stats':
1201
weave_stats(argv[2], ProgressBar())
1203
elif cmd == 'check':
1208
print '%d versions ok' % w.num_versions()
1210
elif cmd == 'inclusions':
1212
print ' '.join(map(str, w.inclusions([int(argv[3])])))
1214
elif cmd == 'parents':
1216
print ' '.join(map(str, w._parents[int(argv[3])]))
1218
elif cmd == 'plan-merge':
1219
# replaced by 'bzr weave-plan-merge'
1221
for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
1223
print '%14s | %s' % (state, line),
1224
elif cmd == 'merge':
1225
# replaced by 'bzr weave-merge-text'
1227
p = w.plan_merge(int(argv[3]), int(argv[4]))
1228
sys.stdout.writelines(w.weave_merge(p))
1230
raise ValueError('unknown command %r' % cmd)
1233
if __name__ == '__main__':
1235
sys.exit(main(sys.argv))