69
71
from copy import copy
70
72
from cStringIO import StringIO
73
78
from bzrlib.lazy_import import lazy_import
74
79
lazy_import(globals(), """
75
80
from bzrlib import tsort
77
82
from bzrlib import (
81
85
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
82
86
RevisionAlreadyPresent,
83
87
RevisionNotPresent,
84
88
UnavailableRepresentation,
89
WeaveRevisionAlreadyPresent,
90
WeaveRevisionNotPresent,
86
from bzrlib.osutils import dirname, sha, sha_strings, split_lines
92
import bzrlib.errors as errors
93
from bzrlib.osutils import dirname, sha_strings, split_lines
87
94
import bzrlib.patiencediff
88
95
from bzrlib.revision import NULL_REVISION
89
96
from bzrlib.symbol_versioning import *
90
97
from bzrlib.trace import mutter
98
from bzrlib.tsort import topo_sort
91
99
from bzrlib.versionedfile import (
92
100
AbsentContentFactory,
98
105
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
699
699
# we're still spending ~1/4 of the method in isinstance though.
700
700
# so lets hard code the acceptable string classes we expect:
701
701
# 449 0 1202.9420 786.2930 bzrlib.weave:556(_extract)
702
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
702
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
704
704
# yay, down to ~1/4 the initial extract time, and our inline time
705
705
# has shrunk again, with isinstance no longer dominating.
706
706
# tweaking the stack inclusion test to use a set gives:
707
707
# 449 0 1122.8030 713.0080 bzrlib.weave:556(_extract)
708
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
708
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
710
710
# - a 5% win, or possibly just noise. However with large istacks that
711
711
# 'in' test could dominate, so I'm leaving this change in place -
712
712
# when its fast enough to consider profiling big datasets we can review.
717
717
for l in self._weave:
718
718
if l.__class__ == tuple:
968
968
super(WeaveFile, self).insert_record_stream(stream)
971
@deprecated_method(one_five)
972
def join(self, other, pb=None, msg=None, version_ids=None,
973
ignore_missing=False):
974
"""Join other into self and save."""
975
super(WeaveFile, self).join(other, pb, msg, version_ids, ignore_missing)
972
979
def _reweave(wa, wb, pb=None, msg=None):
973
980
"""Combine two weaves and return the result.
975
This works even if a revision R has different parents in
982
This works even if a revision R has different parents in
976
983
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
985
This is done by just building up a new weave, maintaining ordering
979
986
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
987
might be possible but it should only be necessary to do
988
this operation rarely, when a new previously ghost version is
984
991
:param pb: An optional progress bar, indicating how far done we are
1029
1035
p = combined.setdefault(name, set())
1030
1036
p.update(map(weave._idx_to_name, weave._parents[idx]))
1031
1037
return combined
1041
"""Show the weave's table-of-contents"""
1042
print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
1043
for i in (6, 50, 10, 10):
1046
for i in range(w.num_versions()):
1049
parent_str = ' '.join(map(str, w._parents[i]))
1050
print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
1054
def weave_stats(weave_file, pb):
1055
from bzrlib.weavefile import read_weave
1057
wf = file(weave_file, 'rb')
1059
# FIXME: doesn't work on pipes
1060
weave_size = wf.tell()
1064
for i in range(vers):
1065
pb.update('checking sizes', i, vers)
1066
for origin, lineno, line in w._extract([i]):
1071
print 'versions %9d' % vers
1072
print 'weave file %9d bytes' % weave_size
1073
print 'total contents %9d bytes' % total
1074
print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
1077
print 'average size %9d bytes' % avg
1078
print 'relative size %9.2fx' % (float(weave_size) / float(avg))
1082
print """bzr weave tool
1084
Experimental tool for weave algorithm.
1087
weave init WEAVEFILE
1088
Create an empty weave file
1089
weave get WEAVEFILE VERSION
1090
Write out specified version.
1091
weave check WEAVEFILE
1092
Check consistency of all versions.
1094
Display table of contents.
1095
weave add WEAVEFILE NAME [BASE...] < NEWTEXT
1096
Add NEWTEXT, with specified parent versions.
1097
weave annotate WEAVEFILE VERSION
1098
Display origin of each line.
1099
weave merge WEAVEFILE VERSION1 VERSION2 > OUT
1100
Auto-merge two versions and display conflicts.
1101
weave diff WEAVEFILE VERSION1 VERSION2
1102
Show differences between two versions.
1106
% weave init foo.weave
1108
% weave add foo.weave ver0 < foo.txt
1111
(create updated version)
1113
% weave get foo.weave 0 | diff -u - foo.txt
1114
% weave add foo.weave ver1 0 < foo.txt
1117
% weave get foo.weave 0 > foo.txt (create forked version)
1119
% weave add foo.weave ver2 0 < foo.txt
1122
% weave merge foo.weave 1 2 > foo.txt (merge them)
1123
% vi foo.txt (resolve conflicts)
1124
% weave add foo.weave merged 1 2 < foo.txt (commit merged version)
1136
# in case we're run directly from the subdirectory
1137
sys.path.append('..')
1139
from bzrlib.weavefile import write_weave, read_weave
1140
from bzrlib.progress import ProgressBar
1155
return read_weave(file(argv[2], 'rb'))
1161
# at the moment, based on everything in the file
1163
parents = map(int, argv[4:])
1164
lines = sys.stdin.readlines()
1165
ver = w.add(name, parents, lines)
1166
write_weave(w, file(argv[2], 'wb'))
1167
print 'added version %r %d' % (name, ver)
1170
if os.path.exists(fn):
1171
raise IOError("file exists")
1173
write_weave(w, file(fn, 'wb'))
1174
elif cmd == 'get': # get one version
1176
sys.stdout.writelines(w.get_iter(int(argv[3])))
1181
v1, v2 = map(int, argv[3:5])
1184
diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
1185
'%s version %d' % (fn, v1),
1186
'%s version %d' % (fn, v2))
1187
sys.stdout.writelines(diff_gen)
1189
elif cmd == 'annotate':
1191
# newline is added to all lines regardless; too hard to get
1192
# reasonable formatting otherwise
1194
for origin, text in w.annotate(int(argv[3])):
1195
text = text.rstrip('\r\n')
1197
print ' | %s' % (text)
1199
print '%5d | %s' % (origin, text)
1205
elif cmd == 'stats':
1206
weave_stats(argv[2], ProgressBar())
1208
elif cmd == 'check':
1213
print '%d versions ok' % w.num_versions()
1215
elif cmd == 'inclusions':
1217
print ' '.join(map(str, w.inclusions([int(argv[3])])))
1219
elif cmd == 'parents':
1221
print ' '.join(map(str, w._parents[int(argv[3])]))
1223
elif cmd == 'plan-merge':
1224
# replaced by 'bzr weave-plan-merge'
1226
for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
1228
print '%14s | %s' % (state, line),
1229
elif cmd == 'merge':
1230
# replaced by 'bzr weave-merge-text'
1232
p = w.plan_merge(int(argv[3]), int(argv[4]))
1233
sys.stdout.writelines(w.weave_merge(p))
1235
raise ValueError('unknown command %r' % cmd)
1238
if __name__ == '__main__':
1240
sys.exit(main(sys.argv))