/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1080 by Martin Pool
- test tool for converting history to weave files
1
# Copyright (C) 2005 Canonical Ltd
1267 by Martin Pool
- notes on conversion of existing history to weaves
2
#
1080 by Martin Pool
- test tool for converting history to weave files
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1267 by Martin Pool
- notes on conversion of existing history to weaves
7
#
1080 by Martin Pool
- test tool for converting history to weave files
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1267 by Martin Pool
- notes on conversion of existing history to weaves
12
#
1080 by Martin Pool
- test tool for converting history to weave files
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1534.4.34 by Robert Collins
Fix remaining uses of deprecated apis within bzrlib.
17
"""bzr upgrade logic."""
18
19
# change upgrade from .bzr to create a '.bzr-new', then do a bait and switch.
20
1080 by Martin Pool
- test tool for converting history to weave files
21
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
22
from cStringIO import StringIO
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
23
import os
1267 by Martin Pool
- notes on conversion of existing history to weaves
24
import tempfile
25
import sys
1534.4.14 by Robert Collins
Replace copy_tree with transport logic in upgreade.
26
from stat import *
1132 by Martin Pool
- fix up logging for history2weaves tool
27
1534.4.28 by Robert Collins
first cut at merge from integration.
28
import bzrlib
1185.65.29 by Robert Collins
Implement final review suggestions.
29
from bzrlib.branch import Branch
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
30
import bzrlib.bzrdir as bzrdir
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
31
from bzrlib.bzrdir import BzrDirFormat, BzrDirFormat4, BzrDirFormat5, BzrDirFormat6
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
32
import bzrlib.errors as errors
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
33
from bzrlib.errors import NoSuchFile, UpgradeReadonly
1534.4.28 by Robert Collins
first cut at merge from integration.
34
from bzrlib.lockable_files import LockableFiles
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
35
from bzrlib.osutils import sha_strings, sha_string, pathjoin, abspath
36
from bzrlib.ui import ui_factory
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
37
from bzrlib.store.text import TextStore
38
from bzrlib.store.weave import WeaveStore
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
39
from bzrlib.trace import mutter, note, warning
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
40
from bzrlib.transactions import PassThroughTransaction
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
41
from bzrlib.transport import get_transport
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
42
from bzrlib.transport.local import LocalTransport
1080 by Martin Pool
- test tool for converting history to weave files
43
from bzrlib.weave import Weave
44
from bzrlib.weavefile import read_weave, write_weave
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
45
from bzrlib.xml4 import serializer_v4
46
from bzrlib.xml5 import serializer_v5
1185.62.12 by John Arbash Meinel
Adding TODO to upgrade.py to remove ancestry.weave
47
48
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
49
class Converter(object):
50
    """Converts a disk format object from one format to another."""
51
52
    def __init__(self, pb):
53
        """Create a converter.
54
55
        :param pb: a progress bar to use for progress information.
56
        """
57
        self.pb = pb
58
59
60
class ConvertBzrDir4To5(Converter):
61
    """Converts format 4 bzr dirs to format 5."""
62
63
    def __init__(self, to_convert, pb):
64
        """Create a converter.
65
66
        :param to_convert: The disk object to convert.
67
        :param pb: a progress bar to use for progress information.
68
        """
69
        super(ConvertBzrDir4To5, self).__init__(pb)
70
        self.bzrdir = to_convert
1307 by Martin Pool
- start walking through ancestors in conversion to weaves
71
        self.converted_revs = set()
72
        self.absent_revisions = set()
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
73
        self.text_count = 0
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
74
        self.revisions = {}
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
75
        
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
76
    def convert(self):
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
77
        """See Converter.convert()."""
78
        self.pb.note('starting upgrade from format 4 to 5')
79
        if isinstance(self.bzrdir.transport, LocalTransport):
80
            self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
81
        self._convert_to_weaves()
82
        return bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
1429 by Robert Collins
merge in niemeyers prefixed-store patch
83
84
    def _convert_to_weaves(self):
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
85
        self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
86
        try:
87
            # TODO permissions
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
88
            stat = self.bzrdir.transport.stat('weaves')
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
89
            if not S_ISDIR(stat.st_mode):
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
90
                self.bzrdir.transport.delete('weaves')
91
                self.bzrdir.transport.mkdir('weaves')
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
92
        except NoSuchFile:
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
93
            self.bzrdir.transport.mkdir('weaves')
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
94
        self.inv_weave = Weave('inventory')
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
95
        # holds in-memory weaves for all files
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
96
        self.text_weaves = {}
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
97
        self.bzrdir.transport.delete('branch-format')
98
        self.branch = self.bzrdir.open_branch()
1381 by Martin Pool
- remove tab characters (only)
99
        self._convert_working_inv()
1358 by Martin Pool
- actually upgrade all of history
100
        rev_history = self.branch.revision_history()
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
101
        # to_read is a stack holding the revisions we still need to process;
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
102
        # appending to it adds new highest-priority revisions
1319 by Martin Pool
- calculate and use file parents for importing texts
103
        self.known_revisions = set(rev_history)
1185.20.1 by Andres Salomon
Handle the case where revision_history() returns an empty list during
104
        self.to_read = rev_history[-1:]
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
105
        while self.to_read:
106
            rev_id = self.to_read.pop()
107
            if (rev_id not in self.revisions
108
                and rev_id not in self.absent_revisions):
109
                self._load_one_rev(rev_id)
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
110
        self.pb.clear()
1332 by Martin Pool
- clean up code that writes out weave results
111
        to_import = self._make_order()
1315 by Martin Pool
- import file inventories in correct order
112
        for i, rev_id in enumerate(to_import):
113
            self.pb.update('converting revision', i, len(to_import))
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
114
            self._convert_one_rev(rev_id)
1331 by Martin Pool
- write out new revisions after conversion
115
        self.pb.clear()
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
116
        self._write_all_weaves()
117
        self._write_all_revs()
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
118
        self.pb.note('upgraded to weaves:')
119
        self.pb.note('  %6d revisions and inventories', len(self.revisions))
120
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
121
        self.pb.note('  %6d texts', self.text_count)
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
122
        self._cleanup_spare_files_after_format4()
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
123
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
1355 by Martin Pool
- write working inventory into final location
124
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
125
    def _cleanup_spare_files_after_format4(self):
1551.2.5 by Aaron Bentley
Removed more selftest spam [recommit]
126
        # FIXME working tree upgrade foo.
1381 by Martin Pool
- remove tab characters (only)
127
        for n in 'merged-patches', 'pending-merged-patches':
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
128
            try:
129
                ## assert os.path.getsize(p) == 0
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
130
                self.bzrdir.transport.delete(n)
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
131
            except NoSuchFile:
132
                pass
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
133
        self.bzrdir.transport.delete_tree('inventory-store')
134
        self.bzrdir.transport.delete_tree('text-store')
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
135
136
    def _convert_working_inv(self):
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
137
        inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
1393.1.18 by Martin Pool
- fix upgrade for transport changes
138
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1551.2.5 by Aaron Bentley
Removed more selftest spam [recommit]
139
        # FIXME inventory is a working tree change.
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
140
        self.branch.control_files.put('inventory', new_inv_xml)
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
141
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
142
    def _write_all_weaves(self):
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
143
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
144
        weave_transport = self.bzrdir.transport.clone('weaves')
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
145
        weaves = WeaveStore(weave_transport, prefixed=False)
146
        transaction = PassThroughTransaction()
147
148
        controlweaves.put_weave('inventory', self.inv_weave, transaction)
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
149
        i = 0
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
150
        try:
151
            for file_id, file_weave in self.text_weaves.items():
152
                self.pb.update('writing weave', i, len(self.text_weaves))
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
153
                weaves.put_weave(file_id, file_weave, transaction)
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
154
                i += 1
155
        finally:
156
            self.pb.clear()
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
157
1331 by Martin Pool
- write out new revisions after conversion
158
    def _write_all_revs(self):
159
        """Write all revisions out in new form."""
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
160
        self.bzrdir.transport.delete_tree('revision-store')
161
        self.bzrdir.transport.mkdir('revision-store')
162
        revision_transport = self.bzrdir.transport.clone('revision-store')
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
163
        # TODO permissions
164
        revision_store = TextStore(revision_transport,
165
                                   prefixed=False,
166
                                   compressed=True)
1331 by Martin Pool
- write out new revisions after conversion
167
        try:
168
            for i, rev_id in enumerate(self.converted_revs):
169
                self.pb.update('write revision', i, len(self.converted_revs))
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
170
                rev_tmp = StringIO()
171
                serializer_v5.write_revision(self.revisions[rev_id], rev_tmp)
172
                rev_tmp.seek(0)
173
                revision_store.add(rev_tmp, rev_id)
1331 by Martin Pool
- write out new revisions after conversion
174
        finally:
175
            self.pb.clear()
1332 by Martin Pool
- clean up code that writes out weave results
176
1331 by Martin Pool
- write out new revisions after conversion
177
            
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
178
    def _load_one_rev(self, rev_id):
179
        """Load a revision object into memory.
180
181
        Any parents not either loaded or abandoned get queued to be
182
        loaded."""
183
        self.pb.update('loading revision',
1315 by Martin Pool
- import file inventories in correct order
184
                       len(self.revisions),
1319 by Martin Pool
- calculate and use file parents for importing texts
185
                       len(self.known_revisions))
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
186
        if not self.branch.repository.revision_store.has_id(rev_id):
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
187
            self.pb.clear()
188
            note('revision {%s} not present in branch; '
1393.1.44 by Martin Pool
- upgrade carries across ghost references
189
                 'will be converted as a ghost',
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
190
                 rev_id)
191
            self.absent_revisions.add(rev_id)
192
        else:
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
193
            rev_xml = self.branch.repository.revision_store.get(rev_id).read()
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
194
            rev = serializer_v4.read_revision_from_string(rev_xml)
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
195
            for parent_id in rev.parent_ids:
1319 by Martin Pool
- calculate and use file parents for importing texts
196
                self.known_revisions.add(parent_id)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
197
                self.to_read.append(parent_id)
198
            self.revisions[rev_id] = rev
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
199
200
201
    def _load_old_inventory(self, rev_id):
202
        assert rev_id not in self.converted_revs
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
203
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
204
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
205
        rev = self.revisions[rev_id]
206
        if rev.inventory_sha1:
207
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
208
                'inventory sha mismatch for {%s}' % rev_id
209
        return inv
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
210
        
211
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
212
    def _load_updated_inventory(self, rev_id):
213
        assert rev_id in self.converted_revs
214
        inv_xml = self.inv_weave.get_text(rev_id)
215
        inv = serializer_v5.read_inventory_from_string(inv_xml)
216
        return inv
217
218
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
219
    def _convert_one_rev(self, rev_id):
220
        """Convert revision and all referenced objects to new format."""
221
        rev = self.revisions[rev_id]
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
222
        inv = self._load_old_inventory(rev_id)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
223
        present_parents = [p for p in rev.parent_ids
224
                           if p not in self.absent_revisions]
225
        self._convert_revision_contents(rev, inv, present_parents)
226
        self._store_new_weave(rev, inv, present_parents)
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
227
        self.converted_revs.add(rev_id)
228
229
1393.1.44 by Martin Pool
- upgrade carries across ghost references
230
    def _store_new_weave(self, rev, inv, present_parents):
1320 by Martin Pool
- write updated inventory into weave
231
        # the XML is now updated with text versions
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
232
        if __debug__:
233
            for file_id in inv:
234
                ie = inv[file_id]
235
                if ie.kind == 'root_directory':
236
                    continue
1092.2.21 by Robert Collins
convert name_version to revision in inventory entries
237
                assert hasattr(ie, 'revision'), \
238
                    'no revision on {%s} in {%s}' % \
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
239
                    (file_id, rev.revision_id)
1316 by Martin Pool
- upgrade format of inventories as they're converted
240
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1325 by Martin Pool
- conversion to weave tries to avoid repeated SHA calculation
241
        new_inv_sha1 = sha_string(new_inv_xml)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
242
        self.inv_weave.add(rev.revision_id, 
243
                           present_parents,
1325 by Martin Pool
- conversion to weave tries to avoid repeated SHA calculation
244
                           new_inv_xml.splitlines(True),
245
                           new_inv_sha1)
246
        rev.inventory_sha1 = new_inv_sha1
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
247
1393.1.44 by Martin Pool
- upgrade carries across ghost references
248
    def _convert_revision_contents(self, rev, inv, present_parents):
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
249
        """Convert all the files within a revision.
250
251
        Also upgrade the inventory to refer to the text revision ids."""
252
        rev_id = rev.revision_id
1319 by Martin Pool
- calculate and use file parents for importing texts
253
        mutter('converting texts of revision {%s}',
254
               rev_id)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
255
        parent_invs = map(self._load_updated_inventory, present_parents)
1332 by Martin Pool
- clean up code that writes out weave results
256
        for file_id in inv:
257
            ie = inv[file_id]
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
258
            self._convert_file_version(rev, ie, parent_invs)
259
260
    def _convert_file_version(self, rev, ie, parent_invs):
1319 by Martin Pool
- calculate and use file parents for importing texts
261
        """Convert one version of one file.
262
263
        The file needs to be added into the weave if it is a merge
264
        of >=2 parents or if it's changed from its parent.
265
        """
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
266
        if ie.kind == 'root_directory':
267
            return
1319 by Martin Pool
- calculate and use file parents for importing texts
268
        file_id = ie.file_id
269
        rev_id = rev.revision_id
270
        w = self.text_weaves.get(file_id)
271
        if w is None:
272
            w = Weave(file_id)
273
            self.text_weaves[file_id] = w
274
        text_changed = False
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
275
        previous_entries = ie.find_previous_heads(parent_invs, w)
1409 by Robert Collins
unify previous inventory entry parent logic in preparation for fixing the revision-thrashing bug
276
        for old_revision in previous_entries:
1092.2.22 by Robert Collins
text_version and name_version unification looking reasonable
277
                # if this fails, its a ghost ?
278
                assert old_revision in self.converted_revs 
1409 by Robert Collins
unify previous inventory entry parent logic in preparation for fixing the revision-thrashing bug
279
        self.snapshot_ie(previous_entries, ie, w, rev_id)
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
280
        del ie.text_id
281
        assert getattr(ie, 'revision', None) is not None
282
283
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
284
        # TODO: convert this logic, which is ~= snapshot to
285
        # a call to:. This needs the path figured out. rather than a work_tree
1409 by Robert Collins
unify previous inventory entry parent logic in preparation for fixing the revision-thrashing bug
286
        # a v4 revision_tree can be given, or something that looks enough like
287
        # one to give the file content to the entry if it needs it.
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
288
        # and we need something that looks like a weave store for snapshot to 
289
        # save against.
290
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
291
        if len(previous_revisions) == 1:
292
            previous_ie = previous_revisions.values()[0]
293
            if ie._unchanged(previous_ie):
294
                ie.revision = previous_ie.revision
295
                return
296
        parent_indexes = map(w.lookup, previous_revisions)
297
        if ie.has_text():
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
298
            text = self.branch.repository.text_store.get(ie.text_id)
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
299
            file_lines = text.readlines()
1378 by Martin Pool
- in upgrade, avoiding loading file texts unless necessary
300
            assert sha_strings(file_lines) == ie.text_sha1
301
            assert sum(map(len, file_lines)) == ie.text_size
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
302
            w.add(rev_id, parent_indexes, file_lines, ie.text_sha1)
1332 by Martin Pool
- clean up code that writes out weave results
303
            self.text_count += 1
1319 by Martin Pool
- calculate and use file parents for importing texts
304
        else:
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
305
            w.add(rev_id, parent_indexes, [], None)
306
        ie.revision = rev_id
307
        ##mutter('import text {%s} of {%s}',
308
        ##       ie.text_id, file_id)
1310 by Martin Pool
- compute order to import revisions
309
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
310
    def _make_order(self):
1310 by Martin Pool
- compute order to import revisions
311
        """Return a suitable order for importing revisions.
312
313
        The order must be such that an revision is imported after all
314
        its (present) parents.
315
        """
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
316
        todo = set(self.revisions.keys())
317
        done = self.absent_revisions.copy()
1310 by Martin Pool
- compute order to import revisions
318
        o = []
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
319
        while todo:
320
            # scan through looking for a revision whose parents
321
            # are all done
1310 by Martin Pool
- compute order to import revisions
322
            for rev_id in sorted(list(todo)):
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
323
                rev = self.revisions[rev_id]
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
324
                parent_ids = set(rev.parent_ids)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
325
                if parent_ids.issubset(done):
326
                    # can take this one now
1310 by Martin Pool
- compute order to import revisions
327
                    o.append(rev_id)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
328
                    todo.remove(rev_id)
329
                    done.add(rev_id)
1315 by Martin Pool
- import file inventories in correct order
330
        return o
1377 by Martin Pool
- run conversion to weaves from the 'bzr upgrade' command
331
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
332
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
333
class ConvertBzrDir5To6(Converter):
334
    """Converts format 5 bzr dirs to format 6."""
335
336
    def __init__(self, to_convert, pb):
337
        """Create a converter.
338
339
        :param to_convert: The disk object to convert.
340
        :param pb: a progress bar to use for progress information.
341
        """
342
        super(ConvertBzrDir5To6, self).__init__(pb)
343
        self.bzrdir = to_convert
344
        
345
    def convert(self):
346
        """See Converter.convert()."""
347
        self.pb.note('starting upgrade from format 5 to 6')
348
        self._convert_to_prefixed()
349
        return bzrdir.BzrDir.open(self.bzrdir.root_transport.base)
350
351
    def _convert_to_prefixed(self):
352
        from bzrlib.store import hash_prefix
353
        self.bzrdir.transport.delete('branch-format')
354
        for store_name in ["weaves", "revision-store"]:
355
            note("adding prefixes to %s" % store_name) 
356
            store_transport = self.bzrdir.transport.clone(store_name)
357
            for filename in store_transport.list_dir('.'):
358
                if (filename.endswith(".weave") or
359
                    filename.endswith(".gz") or
360
                    filename.endswith(".sig")):
361
                    file_id = os.path.splitext(filename)[0]
362
                else:
363
                    file_id = filename
364
                prefix_dir = hash_prefix(file_id)
365
                # FIXME keep track of the dirs made RBC 20060121
366
                try:
367
                    store_transport.move(filename, prefix_dir + '/' + filename)
368
                except NoSuchFile: # catches missing dirs strangely enough
369
                    store_transport.mkdir(prefix_dir)
370
                    store_transport.move(filename, prefix_dir + '/' + filename)
371
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
372
373
374
class Convert(object):
375
376
    def __init__(self, transport):
377
        self.base = transport.base
378
        self.transport = transport
379
        if self.transport.is_readonly():
380
            raise UpgradeReadonly
381
        #  self.control_files = LockableFiles(transport.clone(bzrlib.BZRDIR), 'branch-lock')
382
        # Lock the branch (soon to be meta dir) to prevent anyone racing with us
383
        # This is currently windows incompatible, it will deadlock. When the upgrade
384
        # logic becomes format specific, then we can have the format know how to pass this
385
        # on. Also note that we probably have an 'upgrade meta' which upgrades the constituent
386
        # parts.
387
        # FIXME: control files reuse
388
        # self.control_files.lock_write()
389
        #try:
390
        self.convert()
391
        #finally:
392
        #     self.control_files.unlock()
393
394
    def convert(self):
395
        self.old_format = BzrDirFormat.find_format(self.transport)
396
        self.bzrdir = self.old_format.open(self.transport)
397
        self.branch = self.bzrdir.open_branch()
398
        self.pb = ui_factory.progress_bar()
399
        if isinstance(self.old_format, BzrDirFormat6):
400
            self.pb.note('this branch is in the most current format (%s)', self.old_format)
401
            return
402
        if (not isinstance(self.old_format, BzrDirFormat4) and
403
            not isinstance(self.old_format, BzrDirFormat5) and
404
            not isinstance(self.old_format, bzrdir.BzrDirMetaFormat1)):
405
            raise errors.BzrError("cannot upgrade from branch format %s" %
406
                           self.bzrdir._format)
407
        # return self.bzrdir.upgrade(pb)
408
        self.pb.note('starting upgrade of %s', self.base)
409
        self._backup_control_dir()
410
        if isinstance(self.bzrdir._format, BzrDirFormat4):
411
            converter = ConvertBzrDir4To5(self.bzrdir, self.pb)
412
            self.bzrdir = converter.convert()
413
        if isinstance(self.bzrdir._format, BzrDirFormat5):
414
            converter = ConvertBzrDir5To6(self.bzrdir, self.pb)
415
            self.bzrdir = converter.convert()
416
        self.pb.note("finished")
417
418
    def _backup_control_dir(self):
419
        note('making backup of tree history')
420
        self.transport.copy_tree('.bzr', '.bzr.backup')
421
        note('%s.bzr has been backed up to %s.bzr.backup',
422
             self.transport.base,
423
             self.transport.base)
424
        note('if conversion fails, you can move this directory back to .bzr')
425
        note('if it succeeds, you can remove this directory if you wish')
426
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
427
def upgrade(url):
428
    t = get_transport(url)
429
    Convert(t)