115
111
note('starting upgrade of %s', os.path.abspath(self.base))
116
112
self._backup_control_dir()
117
self.pb = ui_factory.progress_bar()
118
if self.old_format == 4:
119
note('starting upgrade from format 4 to 5')
120
self._convert_to_weaves()
122
if self.old_format == 5:
123
note('starting upgrade from format 5 to 6')
124
self._convert_to_prefixed()
126
cache = hashcache.HashCache(os.path.abspath(self.base))
132
def _convert_to_prefixed(self):
133
from bzrlib.store import hash_prefix
134
for store_name in ["weaves", "revision-store"]:
135
note("adding prefixes to %s" % store_name)
136
store_dir = os.path.join(self.base, ".bzr", store_name)
137
for filename in os.listdir(store_dir):
138
if filename.endswith(".weave") or filename.endswith(".gz"):
139
file_id = os.path.splitext(filename)[0]
142
prefix_dir = os.path.join(store_dir, hash_prefix(file_id))
143
if not os.path.isdir(prefix_dir):
145
os.rename(os.path.join(store_dir, filename),
146
os.path.join(prefix_dir, filename))
147
self._set_new_format(BZR_BRANCH_FORMAT_6)
150
def _convert_to_weaves(self):
113
note('starting upgrade')
151
114
note('note: upgrade may be faster if all store files are ungzipped first')
115
self.pb = ProgressBar()
152
116
if not os.path.isdir(self.base + '/.bzr/weaves'):
153
117
os.mkdir(self.base + '/.bzr/weaves')
154
118
self.inv_weave = Weave('inventory')
119
self.anc_weave = Weave('ancestry')
155
121
# holds in-memory weaves for all files
156
122
self.text_weaves = {}
157
123
os.remove(self.branch.controlfilename('branch-format'))
300
266
"""Convert revision and all referenced objects to new format."""
301
267
rev = self.revisions[rev_id]
302
268
inv = self._load_old_inventory(rev_id)
303
present_parents = [p for p in rev.parent_ids
304
if p not in self.absent_revisions]
305
self._convert_revision_contents(rev, inv, present_parents)
306
self._store_new_weave(rev, inv, present_parents)
269
for parent_id in rev.parent_ids[:]:
270
if parent_id in self.absent_revisions:
271
rev.parent_ids.remove(parent_id)
273
note('remove {%s} as parent of {%s}', parent_id, rev_id)
274
self._convert_revision_contents(rev, inv)
275
self._store_new_weave(rev, inv)
276
self._make_rev_ancestry(rev)
307
277
self.converted_revs.add(rev_id)
310
def _store_new_weave(self, rev, inv, present_parents):
280
def _store_new_weave(self, rev, inv):
311
281
# the XML is now updated with text versions
313
283
for file_id in inv:
314
284
ie = inv[file_id]
315
285
if ie.kind == 'root_directory':
317
assert hasattr(ie, 'revision'), \
318
'no revision on {%s} in {%s}' % \
287
assert hasattr(ie, 'name_version'), \
288
'no name_version on {%s} in {%s}' % \
319
289
(file_id, rev.revision_id)
290
if ie.kind == 'file':
291
assert hasattr(ie, 'text_version')
320
293
new_inv_xml = serializer_v5.write_inventory_to_string(inv)
321
294
new_inv_sha1 = sha_string(new_inv_xml)
322
self.inv_weave.add(rev.revision_id,
295
self.inv_weave.add(rev.revision_id, rev.parent_ids,
324
296
new_inv_xml.splitlines(True),
326
298
rev.inventory_sha1 = new_inv_sha1
328
def _convert_revision_contents(self, rev, inv, present_parents):
301
def _make_rev_ancestry(self, rev):
302
rev_id = rev.revision_id
303
for parent_id in rev.parent_ids:
304
assert parent_id in self.converted_revs
306
lines = list(self.anc_weave.mash_iter(rev.parent_ids))
309
lines.append(rev_id + '\n')
311
parent_ancestries = [self.ancestries[p] for p in rev.parent_ids]
312
new_lines = merge_ancestry_lines(rev_id, parent_ancestries)
313
assert set(lines) == set(new_lines)
314
self.ancestries[rev_id] = new_lines
315
self.anc_weave.add(rev_id, rev.parent_ids, lines)
318
def _convert_revision_contents(self, rev, inv):
329
319
"""Convert all the files within a revision.
331
321
Also upgrade the inventory to refer to the text revision ids."""
332
322
rev_id = rev.revision_id
333
323
mutter('converting texts of revision {%s}',
335
parent_invs = map(self._load_updated_inventory, present_parents)
325
parent_invs = map(self._load_updated_inventory, rev.parent_ids)
336
326
for file_id in inv:
337
327
ie = inv[file_id]
328
self._set_name_version(rev, ie, parent_invs)
329
if ie.kind != 'file':
338
331
self._convert_file_version(rev, ie, parent_invs)
334
def _set_name_version(self, rev, ie, parent_invs):
335
"""Set name version for a file.
337
Done in a slightly lazy way: if the file is renamed or in a merge revision
338
it gets a new version, otherwise the same as before.
341
if ie.kind == 'root_directory':
343
if len(parent_invs) != 1:
344
ie.name_version = rev.revision_id
346
old_inv = parent_invs[0]
347
if not old_inv.has_id(file_id):
348
ie.name_version = rev.revision_id
350
old_ie = old_inv[file_id]
351
if (old_ie.parent_id != ie.parent_id
352
or old_ie.name != ie.name):
353
ie.name_version = rev.revision_id
355
ie.name_version = old_ie.name_version
340
359
def _convert_file_version(self, rev, ie, parent_invs):
341
360
"""Convert one version of one file.
343
362
The file needs to be added into the weave if it is a merge
344
363
of >=2 parents or if it's changed from its parent.
346
if ie.kind == 'root_directory':
348
365
file_id = ie.file_id
349
366
rev_id = rev.revision_id
350
367
w = self.text_weaves.get(file_id)
352
369
w = Weave(file_id)
353
370
self.text_weaves[file_id] = w
354
372
text_changed = False
355
previous_entries = ie.find_previous_heads(parent_invs, w)
356
for old_revision in previous_entries:
357
# if this fails, its a ghost ?
358
assert old_revision in self.converted_revs
359
self.snapshot_ie(previous_entries, ie, w, rev_id)
361
assert getattr(ie, 'revision', None) is not None
363
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
364
# TODO: convert this logic, which is ~= snapshot to
365
# a call to:. This needs the path figured out. rather than a work_tree
366
# a v4 revision_tree can be given, or something that looks enough like
367
# one to give the file content to the entry if it needs it.
368
# and we need something that looks like a weave store for snapshot to
370
#ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
371
if len(previous_revisions) == 1:
372
previous_ie = previous_revisions.values()[0]
373
if ie._unchanged(previous_ie):
374
ie.revision = previous_ie.revision
376
parent_indexes = map(w.lookup, previous_revisions)
378
file_lines = self.branch.text_store.get(ie.text_id).readlines()
373
for parent_inv in parent_invs:
374
if parent_inv.has_id(file_id):
375
parent_ie = parent_inv[file_id]
376
old_text_version = parent_ie.text_version
377
assert old_text_version in self.converted_revs
378
if old_text_version not in file_parents:
379
file_parents.append(old_text_version)
380
if parent_ie.text_sha1 != ie.text_sha1:
382
if len(file_parents) != 1 or text_changed:
383
file_lines = self.branch.text_store[ie.text_id].readlines()
379
384
assert sha_strings(file_lines) == ie.text_sha1
380
385
assert sum(map(len, file_lines)) == ie.text_size
381
w.add(rev_id, parent_indexes, file_lines, ie.text_sha1)
386
w.add(rev_id, file_parents, file_lines, ie.text_sha1)
387
ie.text_version = rev_id
382
388
self.text_count += 1
389
##mutter('import text {%s} of {%s}',
390
## ie.text_id, file_id)
384
w.add(rev_id, parent_indexes, [], None)
386
##mutter('import text {%s} of {%s}',
387
## ie.text_id, file_id)
392
##mutter('text of {%s} unchanged from parent', file_id)
393
ie.text_version = file_parents[0]
389
398
def _make_order(self):
390
399
"""Return a suitable order for importing revisions.