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:
909
904
"""A WeaveFile represents a Weave on disk and writes on change."""
911
906
WEAVE_SUFFIX = '.weave'
913
908
def __init__(self, name, transport, filemode=None, create=False, access_mode='w', get_scope=None):
914
909
"""Create a WeaveFile.
916
911
:param create: If not True, only open an existing knit.
918
super(WeaveFile, self).__init__(name, access_mode, get_scope=get_scope,
919
allow_reserved=False)
913
super(WeaveFile, self).__init__(name, access_mode, get_scope=get_scope)
920
914
self._transport = transport
921
915
self._filemode = filemode
923
f = self._transport.get(name + WeaveFile.WEAVE_SUFFIX)
924
_read_weave_v5(StringIO(f.read()), self)
917
_read_weave_v5(self._transport.get(name + WeaveFile.WEAVE_SUFFIX), self)
925
918
except errors.NoSuchFile:
969
962
super(WeaveFile, self).insert_record_stream(stream)
965
@deprecated_method(one_five)
966
def join(self, other, pb=None, msg=None, version_ids=None,
967
ignore_missing=False):
968
"""Join other into self and save."""
969
super(WeaveFile, self).join(other, pb, msg, version_ids, ignore_missing)
973
973
def _reweave(wa, wb, pb=None, msg=None):
974
974
"""Combine two weaves and return the result.
976
This works even if a revision R has different parents in
976
This works even if a revision R has different parents in
977
977
wa and wb. In the resulting weave all the parents are given.
979
This is done by just building up a new weave, maintaining ordering
979
This is done by just building up a new weave, maintaining ordering
980
980
of the versions in the two inputs. More efficient approaches
981
might be possible but it should only be necessary to do
982
this operation rarely, when a new previously ghost version is
981
might be possible but it should only be necessary to do
982
this operation rarely, when a new previously ghost version is
985
985
:param pb: An optional progress bar, indicating how far done we are
1030
1029
p = combined.setdefault(name, set())
1031
1030
p.update(map(weave._idx_to_name, weave._parents[idx]))
1032
1031
return combined
1035
"""Show the weave's table-of-contents"""
1036
print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
1037
for i in (6, 50, 10, 10):
1040
for i in range(w.num_versions()):
1043
parent_str = ' '.join(map(str, w._parents[i]))
1044
print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
1048
def weave_stats(weave_file, pb):
1049
from bzrlib.weavefile import read_weave
1051
wf = file(weave_file, 'rb')
1053
# FIXME: doesn't work on pipes
1054
weave_size = wf.tell()
1058
for i in range(vers):
1059
pb.update('checking sizes', i, vers)
1060
for origin, lineno, line in w._extract([i]):
1065
print 'versions %9d' % vers
1066
print 'weave file %9d bytes' % weave_size
1067
print 'total contents %9d bytes' % total
1068
print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
1071
print 'average size %9d bytes' % avg
1072
print 'relative size %9.2fx' % (float(weave_size) / float(avg))
1076
print """bzr weave tool
1078
Experimental tool for weave algorithm.
1081
weave init WEAVEFILE
1082
Create an empty weave file
1083
weave get WEAVEFILE VERSION
1084
Write out specified version.
1085
weave check WEAVEFILE
1086
Check consistency of all versions.
1088
Display table of contents.
1089
weave add WEAVEFILE NAME [BASE...] < NEWTEXT
1090
Add NEWTEXT, with specified parent versions.
1091
weave annotate WEAVEFILE VERSION
1092
Display origin of each line.
1093
weave merge WEAVEFILE VERSION1 VERSION2 > OUT
1094
Auto-merge two versions and display conflicts.
1095
weave diff WEAVEFILE VERSION1 VERSION2
1096
Show differences between two versions.
1100
% weave init foo.weave
1102
% weave add foo.weave ver0 < foo.txt
1105
(create updated version)
1107
% weave get foo.weave 0 | diff -u - foo.txt
1108
% weave add foo.weave ver1 0 < foo.txt
1111
% weave get foo.weave 0 > foo.txt (create forked version)
1113
% weave add foo.weave ver2 0 < foo.txt
1116
% weave merge foo.weave 1 2 > foo.txt (merge them)
1117
% vi foo.txt (resolve conflicts)
1118
% weave add foo.weave merged 1 2 < foo.txt (commit merged version)
1130
# in case we're run directly from the subdirectory
1131
sys.path.append('..')
1133
from bzrlib.weavefile import write_weave, read_weave
1134
from bzrlib.progress import ProgressBar
1149
return read_weave(file(argv[2], 'rb'))
1155
# at the moment, based on everything in the file
1157
parents = map(int, argv[4:])
1158
lines = sys.stdin.readlines()
1159
ver = w.add(name, parents, lines)
1160
write_weave(w, file(argv[2], 'wb'))
1161
print 'added version %r %d' % (name, ver)
1164
if os.path.exists(fn):
1165
raise IOError("file exists")
1167
write_weave(w, file(fn, 'wb'))
1168
elif cmd == 'get': # get one version
1170
sys.stdout.writelines(w.get_iter(int(argv[3])))
1175
v1, v2 = map(int, argv[3:5])
1178
diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
1179
'%s version %d' % (fn, v1),
1180
'%s version %d' % (fn, v2))
1181
sys.stdout.writelines(diff_gen)
1183
elif cmd == 'annotate':
1185
# newline is added to all lines regardless; too hard to get
1186
# reasonable formatting otherwise
1188
for origin, text in w.annotate(int(argv[3])):
1189
text = text.rstrip('\r\n')
1191
print ' | %s' % (text)
1193
print '%5d | %s' % (origin, text)
1199
elif cmd == 'stats':
1200
weave_stats(argv[2], ProgressBar())
1202
elif cmd == 'check':
1207
print '%d versions ok' % w.num_versions()
1209
elif cmd == 'inclusions':
1211
print ' '.join(map(str, w.inclusions([int(argv[3])])))
1213
elif cmd == 'parents':
1215
print ' '.join(map(str, w._parents[int(argv[3])]))
1217
elif cmd == 'plan-merge':
1218
# replaced by 'bzr weave-plan-merge'
1220
for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
1222
print '%14s | %s' % (state, line),
1223
elif cmd == 'merge':
1224
# replaced by 'bzr weave-merge-text'
1226
p = w.plan_merge(int(argv[3]), int(argv[4]))
1227
sys.stdout.writelines(w.weave_merge(p))
1229
raise ValueError('unknown command %r' % cmd)
1232
if __name__ == '__main__':
1234
sys.exit(main(sys.argv))