848
834
# no lines outside of insertion blocks, that deletions are
849
835
# properly paired, etc.
837
def _join(self, other, pb, msg, version_ids, ignore_missing):
838
"""Worker routine for join()."""
839
if not other.versions():
840
return # nothing to update, easy
843
# versions is never none, InterWeave checks this.
846
# two loops so that we do not change ourselves before verifying it
848
# work through in index order to make sure we get all dependencies
851
# get the selected versions only that are in other.versions.
852
version_ids = set(other.versions()).intersection(set(version_ids))
853
# pull in the referenced graph.
854
version_ids = other.get_ancestry(version_ids)
855
pending_parents = other.get_parent_map(version_ids)
856
pending_graph = pending_parents.items()
857
if len(pending_graph) != len(version_ids):
858
raise RevisionNotPresent(
859
set(version_ids) - set(pending_parents.keys()), self)
860
for name in topo_sort(pending_graph):
861
other_idx = other._name_map[name]
862
# returns True if we have it, False if we need it.
863
if not self._check_version_consistent(other, other_idx, name):
864
names_to_join.append((other_idx, name))
872
for other_idx, name in names_to_join:
873
# TODO: If all the parents of the other version are already
874
# present then we can avoid some work by just taking the delta
875
# and adjusting the offsets.
876
new_parents = self._imported_parents(other, other_idx)
877
sha1 = other._sha1s[other_idx]
882
pb.update(msg, merged, len(names_to_join))
884
lines = other.get_lines(other_idx)
885
self._add(name, lines, new_parents, sha1)
887
mutter("merged = %d, processed = %d, file_id=%s; deltat=%d"%(
888
merged, processed, self._weave_name, time.time()-time0))
851
890
def _imported_parents(self, other, other_idx):
852
891
"""Return list of parents in self corresponding to indexes in other."""
969
1002
super(WeaveFile, self).insert_record_stream(stream)
1005
@deprecated_method(one_five)
1006
def join(self, other, pb=None, msg=None, version_ids=None,
1007
ignore_missing=False):
1008
"""Join other into self and save."""
1009
super(WeaveFile, self).join(other, pb, msg, version_ids, ignore_missing)
973
1013
def _reweave(wa, wb, pb=None, msg=None):
974
1014
"""Combine two weaves and return the result.
976
This works even if a revision R has different parents in
1016
This works even if a revision R has different parents in
977
1017
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
1019
This is done by just building up a new weave, maintaining ordering
980
1020
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
1021
might be possible but it should only be necessary to do
1022
this operation rarely, when a new previously ghost version is
985
1025
:param pb: An optional progress bar, indicating how far done we are
1030
1069
p = combined.setdefault(name, set())
1031
1070
p.update(map(weave._idx_to_name, weave._parents[idx]))
1032
1071
return combined
1075
"""Show the weave's table-of-contents"""
1076
print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
1077
for i in (6, 50, 10, 10):
1080
for i in range(w.num_versions()):
1083
parent_str = ' '.join(map(str, w._parents[i]))
1084
print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
1088
def weave_stats(weave_file, pb):
1089
from bzrlib.weavefile import read_weave
1091
wf = file(weave_file, 'rb')
1093
# FIXME: doesn't work on pipes
1094
weave_size = wf.tell()
1098
for i in range(vers):
1099
pb.update('checking sizes', i, vers)
1100
for origin, lineno, line in w._extract([i]):
1105
print 'versions %9d' % vers
1106
print 'weave file %9d bytes' % weave_size
1107
print 'total contents %9d bytes' % total
1108
print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
1111
print 'average size %9d bytes' % avg
1112
print 'relative size %9.2fx' % (float(weave_size) / float(avg))
1116
print """bzr weave tool
1118
Experimental tool for weave algorithm.
1121
weave init WEAVEFILE
1122
Create an empty weave file
1123
weave get WEAVEFILE VERSION
1124
Write out specified version.
1125
weave check WEAVEFILE
1126
Check consistency of all versions.
1128
Display table of contents.
1129
weave add WEAVEFILE NAME [BASE...] < NEWTEXT
1130
Add NEWTEXT, with specified parent versions.
1131
weave annotate WEAVEFILE VERSION
1132
Display origin of each line.
1133
weave merge WEAVEFILE VERSION1 VERSION2 > OUT
1134
Auto-merge two versions and display conflicts.
1135
weave diff WEAVEFILE VERSION1 VERSION2
1136
Show differences between two versions.
1140
% weave init foo.weave
1142
% weave add foo.weave ver0 < foo.txt
1145
(create updated version)
1147
% weave get foo.weave 0 | diff -u - foo.txt
1148
% weave add foo.weave ver1 0 < foo.txt
1151
% weave get foo.weave 0 > foo.txt (create forked version)
1153
% weave add foo.weave ver2 0 < foo.txt
1156
% weave merge foo.weave 1 2 > foo.txt (merge them)
1157
% vi foo.txt (resolve conflicts)
1158
% weave add foo.weave merged 1 2 < foo.txt (commit merged version)
1170
# in case we're run directly from the subdirectory
1171
sys.path.append('..')
1173
from bzrlib.weavefile import write_weave, read_weave
1174
from bzrlib.progress import ProgressBar
1189
return read_weave(file(argv[2], 'rb'))
1195
# at the moment, based on everything in the file
1197
parents = map(int, argv[4:])
1198
lines = sys.stdin.readlines()
1199
ver = w.add(name, parents, lines)
1200
write_weave(w, file(argv[2], 'wb'))
1201
print 'added version %r %d' % (name, ver)
1204
if os.path.exists(fn):
1205
raise IOError("file exists")
1207
write_weave(w, file(fn, 'wb'))
1208
elif cmd == 'get': # get one version
1210
sys.stdout.writelines(w.get_iter(int(argv[3])))
1215
v1, v2 = map(int, argv[3:5])
1218
diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
1219
'%s version %d' % (fn, v1),
1220
'%s version %d' % (fn, v2))
1221
sys.stdout.writelines(diff_gen)
1223
elif cmd == 'annotate':
1225
# newline is added to all lines regardless; too hard to get
1226
# reasonable formatting otherwise
1228
for origin, text in w.annotate(int(argv[3])):
1229
text = text.rstrip('\r\n')
1231
print ' | %s' % (text)
1233
print '%5d | %s' % (origin, text)
1239
elif cmd == 'stats':
1240
weave_stats(argv[2], ProgressBar())
1242
elif cmd == 'check':
1247
print '%d versions ok' % w.num_versions()
1249
elif cmd == 'inclusions':
1251
print ' '.join(map(str, w.inclusions([int(argv[3])])))
1253
elif cmd == 'parents':
1255
print ' '.join(map(str, w._parents[int(argv[3])]))
1257
elif cmd == 'plan-merge':
1258
# replaced by 'bzr weave-plan-merge'
1260
for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
1262
print '%14s | %s' % (state, line),
1263
elif cmd == 'merge':
1264
# replaced by 'bzr weave-merge-text'
1266
p = w.plan_merge(int(argv[3]), int(argv[4]))
1267
sys.stdout.writelines(w.weave_merge(p))
1269
raise ValueError('unknown command %r' % cmd)
1272
if __name__ == '__main__':
1274
sys.exit(main(sys.argv))
1277
class InterWeave(InterVersionedFile):
1278
"""Optimised code paths for weave to weave operations."""
1280
_matching_file_from_factory = staticmethod(WeaveFile)
1281
_matching_file_to_factory = staticmethod(WeaveFile)
1284
def is_compatible(source, target):
1285
"""Be compatible with weaves."""
1287
return (isinstance(source, Weave) and
1288
isinstance(target, Weave))
1289
except AttributeError:
1292
def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
1293
"""See InterVersionedFile.join."""
1294
version_ids = self._get_source_version_ids(version_ids, ignore_missing)
1295
if self.target.versions() == [] and version_ids is None:
1296
self.target._copy_weave_content(self.source)
1298
self.target._join(self.source, pb, msg, version_ids, ignore_missing)
1301
InterVersionedFile.register_optimiser(InterWeave)