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
215
216
__slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map',
216
'_weave_name', '_matcher', '_allow_reserved']
218
def __init__(self, weave_name=None, access_mode='w', matcher=None,
219
get_scope=None, allow_reserved=False):
217
'_weave_name', '_matcher']
219
def __init__(self, weave_name=None, access_mode='w', matcher=None, get_scope=None):
220
220
"""Create a weave.
222
222
:param get_scope: A callable that returns an opaque object to be used
223
223
for detecting when this weave goes out of scope (should stop
224
224
answering requests or allowing mutation).
226
super(Weave, self).__init__()
226
super(Weave, self).__init__(access_mode)
228
228
self._parents = []
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
959
super(WeaveFile, self).insert_record_stream(stream)
962
@deprecated_method(one_five)
963
def join(self, other, pb=None, msg=None, version_ids=None,
964
ignore_missing=False):
965
"""Join other into self and save."""
966
super(WeaveFile, self).join(other, pb, msg, version_ids, ignore_missing)
972
970
def _reweave(wa, wb, pb=None, msg=None):
973
971
"""Combine two weaves and return the result.
975
This works even if a revision R has different parents in
973
This works even if a revision R has different parents in
976
974
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
976
This is done by just building up a new weave, maintaining ordering
979
977
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
978
might be possible but it should only be necessary to do
979
this operation rarely, when a new previously ghost version is
984
982
:param pb: An optional progress bar, indicating how far done we are
1029
1026
p = combined.setdefault(name, set())
1030
1027
p.update(map(weave._idx_to_name, weave._parents[idx]))
1031
1028
return combined
1032
"""Show the weave's table-of-contents"""
1033
print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
1034
for i in (6, 50, 10, 10):
1037
for i in range(w.num_versions()):
1040
parent_str = ' '.join(map(str, w._parents[i]))
1041
print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
1045
def weave_stats(weave_file, pb):
1046
from bzrlib.weavefile import read_weave
1048
wf = file(weave_file, 'rb')
1050
# FIXME: doesn't work on pipes
1051
weave_size = wf.tell()
1055
for i in range(vers):
1056
pb.update('checking sizes', i, vers)
1057
for origin, lineno, line in w._extract([i]):
1062
print 'versions %9d' % vers
1063
print 'weave file %9d bytes' % weave_size
1064
print 'total contents %9d bytes' % total
1065
print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
1068
print 'average size %9d bytes' % avg
1069
print 'relative size %9.2fx' % (float(weave_size) / float(avg))
1073
print """bzr weave tool
1075
Experimental tool for weave algorithm.
1078
weave init WEAVEFILE
1079
Create an empty weave file
1080
weave get WEAVEFILE VERSION
1081
Write out specified version.
1082
weave check WEAVEFILE
1083
Check consistency of all versions.
1085
Display table of contents.
1086
weave add WEAVEFILE NAME [BASE...] < NEWTEXT
1087
Add NEWTEXT, with specified parent versions.
1088
weave annotate WEAVEFILE VERSION
1089
Display origin of each line.
1090
weave merge WEAVEFILE VERSION1 VERSION2 > OUT
1091
Auto-merge two versions and display conflicts.
1092
weave diff WEAVEFILE VERSION1 VERSION2
1093
Show differences between two versions.
1097
% weave init foo.weave
1099
% weave add foo.weave ver0 < foo.txt
1102
(create updated version)
1104
% weave get foo.weave 0 | diff -u - foo.txt
1105
% weave add foo.weave ver1 0 < foo.txt
1108
% weave get foo.weave 0 > foo.txt (create forked version)
1110
% weave add foo.weave ver2 0 < foo.txt
1113
% weave merge foo.weave 1 2 > foo.txt (merge them)
1114
% vi foo.txt (resolve conflicts)
1115
% weave add foo.weave merged 1 2 < foo.txt (commit merged version)
1127
# in case we're run directly from the subdirectory
1128
sys.path.append('..')
1130
from bzrlib.weavefile import write_weave, read_weave
1131
from bzrlib.progress import ProgressBar
1146
return read_weave(file(argv[2], 'rb'))
1152
# at the moment, based on everything in the file
1154
parents = map(int, argv[4:])
1155
lines = sys.stdin.readlines()
1156
ver = w.add(name, parents, lines)
1157
write_weave(w, file(argv[2], 'wb'))
1158
print 'added version %r %d' % (name, ver)
1161
if os.path.exists(fn):
1162
raise IOError("file exists")
1164
write_weave(w, file(fn, 'wb'))
1165
elif cmd == 'get': # get one version
1167
sys.stdout.writelines(w.get_iter(int(argv[3])))
1172
v1, v2 = map(int, argv[3:5])
1175
diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
1176
'%s version %d' % (fn, v1),
1177
'%s version %d' % (fn, v2))
1178
sys.stdout.writelines(diff_gen)
1180
elif cmd == 'annotate':
1182
# newline is added to all lines regardless; too hard to get
1183
# reasonable formatting otherwise
1185
for origin, text in w.annotate(int(argv[3])):
1186
text = text.rstrip('\r\n')
1188
print ' | %s' % (text)
1190
print '%5d | %s' % (origin, text)
1196
elif cmd == 'stats':
1197
weave_stats(argv[2], ProgressBar())
1199
elif cmd == 'check':
1204
print '%d versions ok' % w.num_versions()
1206
elif cmd == 'inclusions':
1208
print ' '.join(map(str, w.inclusions([int(argv[3])])))
1210
elif cmd == 'parents':
1212
print ' '.join(map(str, w._parents[int(argv[3])]))
1214
elif cmd == 'plan-merge':
1215
# replaced by 'bzr weave-plan-merge'
1217
for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
1219
print '%14s | %s' % (state, line),
1220
elif cmd == 'merge':
1221
# replaced by 'bzr weave-merge-text'
1223
p = w.plan_merge(int(argv[3]), int(argv[4]))
1224
sys.stdout.writelines(w.weave_merge(p))
1226
raise ValueError('unknown command %r' % cmd)
1229
if __name__ == '__main__':
1231
sys.exit(main(sys.argv))