~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/upgrade.py

  • Committer: Robert Collins
  • Date: 2005-09-29 02:01:49 UTC
  • Revision ID: robertc@robertcollins.net-20050929020149-1ff16722c6a01b2c
reenable remotebranch tests

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()
149
149
 
150
150
 
151
151
    def _open_branch(self):
152
 
        self.branch = Branch.open_downlevel(self.base)
 
152
        self.branch = Branch(self.base, relax_version_check=True)
153
153
        if self.branch._branch_format == 5:
154
154
            note('this branch is already in the most current format')
155
155
            return False
160
160
 
161
161
 
162
162
    def _set_new_format(self):
163
 
        self.branch.put_controlfile('branch-format', BZR_BRANCH_FORMAT_5)
 
163
        f = self.branch.controlfile('branch-format', 'wb')
 
164
        try:
 
165
            f.write(BZR_BRANCH_FORMAT_5)
 
166
        finally:
 
167
            f.close()
164
168
 
165
169
 
166
170
    def _cleanup_spare_files(self):
187
191
    def _convert_working_inv(self):
188
192
        branch = self.branch
189
193
        inv = serializer_v4.read_inventory(branch.controlfile('inventory', 'rb'))
190
 
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
191
 
        branch.put_controlfile('inventory', new_inv_xml)
 
194
        serializer_v5.write_inventory(inv, branch.controlfile('inventory', 'wb'))
192
195
 
193
196
 
194
197
 
195
198
    def _write_all_weaves(self):
196
199
        write_a_weave(self.inv_weave, self.base + '/.bzr/inventory.weave')
 
200
        write_a_weave(self.anc_weave, self.base + '/.bzr/ancestry.weave')
197
201
        i = 0
198
202
        try:
199
203
            for file_id, file_weave in self.text_weaves.items():
231
235
        if rev_id not in self.branch.revision_store:
232
236
            self.pb.clear()
233
237
            note('revision {%s} not present in branch; '
234
 
                 'will be converted as a ghost',
 
238
                 'will not be converted',
235
239
                 rev_id)
236
240
            self.absent_revisions.add(rev_id)
237
241
        else:
265
269
        """Convert revision and all referenced objects to new format."""
266
270
        rev = self.revisions[rev_id]
267
271
        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)
 
272
        for parent_id in rev.parent_ids[:]:
 
273
            if parent_id in self.absent_revisions:
 
274
                rev.parent_ids.remove(parent_id)
 
275
                self.pb.clear()
 
276
                note('remove {%s} as parent of {%s}', parent_id, rev_id)
 
277
        self._convert_revision_contents(rev, inv)
 
278
        self._store_new_weave(rev, inv)
 
279
        self._make_rev_ancestry(rev)
272
280
        self.converted_revs.add(rev_id)
273
281
 
274
282
 
275
 
    def _store_new_weave(self, rev, inv, present_parents):
 
283
    def _store_new_weave(self, rev, inv):
276
284
        # the XML is now updated with text versions
277
285
        if __debug__:
278
286
            for file_id in inv:
279
287
                ie = inv[file_id]
280
288
                if ie.kind == 'root_directory':
281
289
                    continue
282
 
                assert hasattr(ie, 'revision'), \
283
 
                    'no revision on {%s} in {%s}' % \
 
290
                assert hasattr(ie, 'name_version'), \
 
291
                    'no name_version on {%s} in {%s}' % \
284
292
                    (file_id, rev.revision_id)
 
293
                if ie.kind == 'file':
 
294
                    assert hasattr(ie, 'text_version')
 
295
 
285
296
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
286
297
        new_inv_sha1 = sha_string(new_inv_xml)
287
 
        self.inv_weave.add(rev.revision_id, 
288
 
                           present_parents,
 
298
        self.inv_weave.add(rev.revision_id, rev.parent_ids,
289
299
                           new_inv_xml.splitlines(True),
290
300
                           new_inv_sha1)
291
301
        rev.inventory_sha1 = new_inv_sha1
292
302
 
293
 
    def _convert_revision_contents(self, rev, inv, present_parents):
 
303
 
 
304
    def _make_rev_ancestry(self, rev):
 
305
        rev_id = rev.revision_id
 
306
        for parent_id in rev.parent_ids:
 
307
            assert parent_id in self.converted_revs
 
308
        if rev.parent_ids:
 
309
            lines = list(self.anc_weave.mash_iter(rev.parent_ids))
 
310
        else:
 
311
            lines = []
 
312
        lines.append(rev_id + '\n')
 
313
        if __debug__:
 
314
            parent_ancestries = [self.ancestries[p] for p in rev.parent_ids]
 
315
            new_lines = merge_ancestry_lines(rev_id, parent_ancestries)
 
316
            assert set(lines) == set(new_lines)
 
317
            self.ancestries[rev_id] = new_lines
 
318
        self.anc_weave.add(rev_id, rev.parent_ids, lines)
 
319
 
 
320
 
 
321
    def _convert_revision_contents(self, rev, inv):
294
322
        """Convert all the files within a revision.
295
323
 
296
324
        Also upgrade the inventory to refer to the text revision ids."""
297
325
        rev_id = rev.revision_id
298
326
        mutter('converting texts of revision {%s}',
299
327
               rev_id)
300
 
        parent_invs = map(self._load_updated_inventory, present_parents)
 
328
        parent_invs = map(self._load_updated_inventory, rev.parent_ids)
301
329
        for file_id in inv:
302
330
            ie = inv[file_id]
 
331
            self._set_name_version(rev, ie, parent_invs)
 
332
            if ie.kind != 'file':
 
333
                continue
303
334
            self._convert_file_version(rev, ie, parent_invs)
304
335
 
 
336
 
 
337
    def _set_name_version(self, rev, ie, parent_invs):
 
338
        """Set name version for a file.
 
339
 
 
340
        Done in a slightly lazy way: if the file is renamed or in a merge revision
 
341
        it gets a new version, otherwise the same as before.
 
342
        """
 
343
        file_id = ie.file_id
 
344
        if ie.kind == 'root_directory':
 
345
            return
 
346
        if len(parent_invs) != 1:
 
347
            ie.name_version = rev.revision_id
 
348
        else:
 
349
            old_inv = parent_invs[0]
 
350
            if not old_inv.has_id(file_id):
 
351
                ie.name_version = rev.revision_id
 
352
            else:
 
353
                old_ie = old_inv[file_id]
 
354
                if (old_ie.parent_id != ie.parent_id
 
355
                    or old_ie.name != ie.name):
 
356
                    ie.name_version = rev.revision_id
 
357
                else:
 
358
                    ie.name_version = old_ie.name_version
 
359
 
 
360
 
 
361
 
305
362
    def _convert_file_version(self, rev, ie, parent_invs):
306
363
        """Convert one version of one file.
307
364
 
308
365
        The file needs to be added into the weave if it is a merge
309
366
        of >=2 parents or if it's changed from its parent.
310
367
        """
311
 
        if ie.kind == 'root_directory':
312
 
            return
313
368
        file_id = ie.file_id
314
369
        rev_id = rev.revision_id
315
370
        w = self.text_weaves.get(file_id)
316
371
        if w is None:
317
372
            w = Weave(file_id)
318
373
            self.text_weaves[file_id] = w
 
374
        file_parents = []
319
375
        text_changed = False
320
 
        previous_entries = ie.find_previous_heads(parent_invs, w)
321
 
        for old_revision in previous_entries:
322
 
                # if this fails, its a ghost ?
323
 
                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():
 
376
        for parent_inv in parent_invs:
 
377
            if parent_inv.has_id(file_id):
 
378
                parent_ie = parent_inv[file_id]
 
379
                old_text_version = parent_ie.text_version
 
380
                assert old_text_version in self.converted_revs 
 
381
                if old_text_version not in file_parents:
 
382
                    file_parents.append(old_text_version)
 
383
                if parent_ie.text_sha1 != ie.text_sha1:
 
384
                    text_changed = True
 
385
        if len(file_parents) != 1 or text_changed:
343
386
            file_lines = self.branch.text_store[ie.text_id].readlines()
344
387
            assert sha_strings(file_lines) == ie.text_sha1
345
388
            assert sum(map(len, file_lines)) == ie.text_size
346
 
            w.add(rev_id, parent_indexes, file_lines, ie.text_sha1)
 
389
            w.add(rev_id, file_parents, file_lines, ie.text_sha1)
 
390
            ie.text_version = rev_id
347
391
            self.text_count += 1
 
392
            ##mutter('import text {%s} of {%s}',
 
393
            ##       ie.text_id, file_id)
348
394
        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)
 
395
            ##mutter('text of {%s} unchanged from parent', file_id)
 
396
            ie.text_version = file_parents[0]
 
397
        del ie.text_id
 
398
 
 
399
 
353
400
 
354
401
    def _make_order(self):
355
402
        """Return a suitable order for importing revisions.