~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/upgrade.py

  • Committer: Robert Collins
  • Date: 2005-10-04 04:38:48 UTC
  • mfrom: (1400.1.1)
  • Revision ID: robertc@robertcollins.net-20051004043848-d65bb5f9d435fbb3
unbreak http branch operations

Show diffs side-by-side

added added

removed removed

Lines of Context:
68
68
# versions.
69
69
 
70
70
 
71
 
# TODO: Don't create a progress bar here, have it passed by the caller.  
72
 
# At least do it from the UI factory.
73
 
 
74
71
if False:
75
72
    try:
76
73
        import psyco
89
86
from bzrlib.revfile import Revfile
90
87
from bzrlib.weave import Weave
91
88
from bzrlib.weavefile import read_weave, write_weave
92
 
from bzrlib.ui import ui_factory
 
89
from bzrlib.progress import ProgressBar
93
90
from bzrlib.atomicfile import AtomicFile
94
91
from bzrlib.xml4 import serializer_v4
95
92
from bzrlib.xml5 import serializer_v5
96
93
from bzrlib.trace import mutter, note, warning, enable_default_logging
97
94
from bzrlib.osutils import sha_strings, sha_string
 
95
from bzrlib.commit import merge_ancestry_lines
98
96
 
99
97
 
100
98
class Convert(object):
114
112
        self._backup_control_dir()
115
113
        note('starting upgrade')
116
114
        note('note: upgrade may be faster if all store files are ungzipped first')
117
 
        self.pb = ui_factory.progress_bar()
 
115
        self.pb = ProgressBar()
118
116
        if not os.path.isdir(self.base + '/.bzr/weaves'):
119
117
            os.mkdir(self.base + '/.bzr/weaves')
120
118
        self.inv_weave = Weave('inventory')
 
119
        self.anc_weave = Weave('ancestry')
 
120
        self.ancestries = {}
121
121
        # holds in-memory weaves for all files
122
122
        self.text_weaves = {}
123
123
        os.remove(self.branch.controlfilename('branch-format'))
140
140
        self.pb.clear()
141
141
        note('upgraded to weaves:')
142
142
        note('  %6d revisions and inventories' % len(self.revisions))
143
 
        note('  %6d revisions not present' % len(self.absent_revisions))
 
143
        note('  %6d absent revisions removed' % len(self.absent_revisions))
144
144
        note('  %6d texts' % self.text_count)
145
145
        self._write_all_weaves()
146
146
        self._write_all_revs()
194
194
 
195
195
    def _write_all_weaves(self):
196
196
        write_a_weave(self.inv_weave, self.base + '/.bzr/inventory.weave')
 
197
        write_a_weave(self.anc_weave, self.base + '/.bzr/ancestry.weave')
197
198
        i = 0
198
199
        try:
199
200
            for file_id, file_weave in self.text_weaves.items():
231
232
        if rev_id not in self.branch.revision_store:
232
233
            self.pb.clear()
233
234
            note('revision {%s} not present in branch; '
234
 
                 'will be converted as a ghost',
 
235
                 'will not be converted',
235
236
                 rev_id)
236
237
            self.absent_revisions.add(rev_id)
237
238
        else:
265
266
        """Convert revision and all referenced objects to new format."""
266
267
        rev = self.revisions[rev_id]
267
268
        inv = self._load_old_inventory(rev_id)
268
 
        present_parents = [p for p in rev.parent_ids
269
 
                           if p not in self.absent_revisions]
270
 
        self._convert_revision_contents(rev, inv, present_parents)
271
 
        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)
 
272
                self.pb.clear()
 
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)
272
277
        self.converted_revs.add(rev_id)
273
278
 
274
279
 
275
 
    def _store_new_weave(self, rev, inv, present_parents):
 
280
    def _store_new_weave(self, rev, inv):
276
281
        # the XML is now updated with text versions
277
282
        if __debug__:
278
283
            for file_id in inv:
282
287
                assert hasattr(ie, 'revision'), \
283
288
                    'no revision on {%s} in {%s}' % \
284
289
                    (file_id, rev.revision_id)
 
290
 
285
291
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
286
292
        new_inv_sha1 = sha_string(new_inv_xml)
287
 
        self.inv_weave.add(rev.revision_id, 
288
 
                           present_parents,
 
293
        self.inv_weave.add(rev.revision_id, rev.parent_ids,
289
294
                           new_inv_xml.splitlines(True),
290
295
                           new_inv_sha1)
291
296
        rev.inventory_sha1 = new_inv_sha1
292
297
 
293
 
    def _convert_revision_contents(self, rev, inv, present_parents):
 
298
 
 
299
    def _make_rev_ancestry(self, rev):
 
300
        rev_id = rev.revision_id
 
301
        for parent_id in rev.parent_ids:
 
302
            assert parent_id in self.converted_revs
 
303
        if rev.parent_ids:
 
304
            lines = list(self.anc_weave.mash_iter(rev.parent_ids))
 
305
        else:
 
306
            lines = []
 
307
        lines.append(rev_id + '\n')
 
308
        if __debug__:
 
309
            parent_ancestries = [self.ancestries[p] for p in rev.parent_ids]
 
310
            new_lines = merge_ancestry_lines(rev_id, parent_ancestries)
 
311
            assert set(lines) == set(new_lines)
 
312
            self.ancestries[rev_id] = new_lines
 
313
        self.anc_weave.add(rev_id, rev.parent_ids, lines)
 
314
 
 
315
 
 
316
    def _convert_revision_contents(self, rev, inv):
294
317
        """Convert all the files within a revision.
295
318
 
296
319
        Also upgrade the inventory to refer to the text revision ids."""
297
320
        rev_id = rev.revision_id
298
321
        mutter('converting texts of revision {%s}',
299
322
               rev_id)
300
 
        parent_invs = map(self._load_updated_inventory, present_parents)
 
323
        parent_invs = map(self._load_updated_inventory, rev.parent_ids)
301
324
        for file_id in inv:
302
325
            ie = inv[file_id]
 
326
            self._set_revision(rev, ie, parent_invs)
 
327
            if not ie.has_text():
 
328
                continue
303
329
            self._convert_file_version(rev, ie, parent_invs)
304
330
 
 
331
 
 
332
    def _set_revision(self, rev, ie, parent_invs):
 
333
        """Set name version for a file.
 
334
 
 
335
        Done in a slightly lazy way: if the file is renamed or in a merge revision
 
336
        it gets a new version, otherwise the same as before.
 
337
        """
 
338
        file_id = ie.file_id
 
339
        if ie.kind == 'root_directory':
 
340
            return
 
341
        if len(parent_invs) != 1:
 
342
            ie.revision = rev.revision_id
 
343
        else:
 
344
            old_inv = parent_invs[0]
 
345
            if not old_inv.has_id(file_id):
 
346
                ie.revision = rev.revision_id
 
347
            else:
 
348
                old_ie = old_inv[file_id]
 
349
                if (old_ie.parent_id != ie.parent_id
 
350
                    or old_ie.name != ie.name):
 
351
                    ie.revision = rev.revision_id
 
352
                else:
 
353
                    ie.revision = old_ie.revision
 
354
 
 
355
 
 
356
 
305
357
    def _convert_file_version(self, rev, ie, parent_invs):
306
358
        """Convert one version of one file.
307
359
 
308
360
        The file needs to be added into the weave if it is a merge
309
361
        of >=2 parents or if it's changed from its parent.
310
362
        """
311
 
        if ie.kind == 'root_directory':
312
 
            return
313
363
        file_id = ie.file_id
314
364
        rev_id = rev.revision_id
315
365
        w = self.text_weaves.get(file_id)
316
366
        if w is None:
317
367
            w = Weave(file_id)
318
368
            self.text_weaves[file_id] = w
 
369
        file_parents = []
319
370
        text_changed = False
320
 
        previous_entries = ie.find_previous_heads(parent_invs, w)
321
 
        for old_revision in previous_entries:
 
371
        for parent_inv in parent_invs:
 
372
            if parent_inv.has_id(file_id):
 
373
                parent_ie = parent_inv[file_id]
 
374
                old_revision = parent_ie.revision
322
375
                # if this fails, its a ghost ?
323
376
                assert old_revision in self.converted_revs 
324
 
        self.snapshot_ie(previous_entries, ie, w, rev_id)
325
 
        del ie.text_id
326
 
        assert getattr(ie, 'revision', None) is not None
327
 
 
328
 
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
329
 
        # TODO: convert this logic, which is ~= snapshot to
330
 
        # a call to:. This needs the path figured out. rather than a work_tree
331
 
        # a v4 revision_tree can be given, or something that looks enough like
332
 
        # one to give the file content to the entry if it needs it.
333
 
        # and we need something that looks like a weave store for snapshot to 
334
 
        # save against.
335
 
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
336
 
        if len(previous_revisions) == 1:
337
 
            previous_ie = previous_revisions.values()[0]
338
 
            if ie._unchanged(previous_ie):
339
 
                ie.revision = previous_ie.revision
340
 
                return
341
 
        parent_indexes = map(w.lookup, previous_revisions)
342
 
        if ie.has_text():
 
377
                if old_revision not in file_parents:
 
378
                    file_parents.append(old_revision)
 
379
                if parent_ie.text_sha1 != ie.text_sha1:
 
380
                    text_changed = True
 
381
        if len(file_parents) != 1 or text_changed:
343
382
            file_lines = self.branch.text_store[ie.text_id].readlines()
344
383
            assert sha_strings(file_lines) == ie.text_sha1
345
384
            assert sum(map(len, file_lines)) == ie.text_size
346
 
            w.add(rev_id, parent_indexes, file_lines, ie.text_sha1)
 
385
            w.add(rev_id, file_parents, file_lines, ie.text_sha1)
 
386
            ie.revision = rev_id
347
387
            self.text_count += 1
 
388
            ##mutter('import text {%s} of {%s}',
 
389
            ##       ie.text_id, file_id)
348
390
        else:
349
 
            w.add(rev_id, parent_indexes, [], None)
350
 
        ie.revision = rev_id
351
 
        ##mutter('import text {%s} of {%s}',
352
 
        ##       ie.text_id, file_id)
 
391
            ##mutter('text of {%s} unchanged from parent', file_id)
 
392
            ie.revision = file_parents[0]
 
393
        del ie.text_id
 
394
 
 
395
 
353
396
 
354
397
    def _make_order(self):
355
398
        """Return a suitable order for importing revisions.