~bzr-pqm/bzr/bzr.dev

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
17
"""Experiment in converting existing bzr branches to weaves."""
18
1267 by Martin Pool
- notes on conversion of existing history to weaves
19
# To make this properly useful
20
#
21
# 1. assign text version ids, and put those text versions into
22
#    the inventory as they're converted.
23
#
24
# 2. keep track of the previous version of each file, rather than
25
#    just using the last one imported
26
#
27
# 3. assign entry versions when files are added, renamed or moved.
28
#
29
# 4. when merged-in versions are observed, walk down through them
30
#    to discover everything, then commit bottom-up
31
#
32
# 5. track ancestry as things are merged in, and commit that in each
33
#    revision
34
#
35
# Perhaps it's best to first walk the whole graph and make a plan for
36
# what should be imported in what order?  Need a kind of topological
37
# sort of all revisions.  (Or do we, can we just before doing a revision
38
# see that all its parents have either been converted or abandoned?)
39
1315 by Martin Pool
- import file inventories in correct order
40
41
# Cannot import a revision until all its parents have been
42
# imported.  in other words, we can only import revisions whose
43
# parents have all been imported.  the first step must be to
44
# import a revision with no parents, of which there must be at
45
# least one.  (So perhaps it's useful to store forward pointers
46
# from a list of parents to their children?)
47
#
48
# Another (equivalent?) approach is to build up the ordered
49
# ancestry list for the last revision, and walk through that.  We
50
# are going to need that.
51
#
52
# We don't want to have to recurse all the way back down the list.
53
#
54
# Suppose we keep a queue of the revisions able to be processed at
55
# any point.  This starts out with all the revisions having no
56
# parents.
57
#
58
# This seems like a generally useful algorithm...
59
#
60
# The current algorithm is dumb (O(n**2)?) but will do the job, and
61
# takes less than a second on the bzr.dev branch.
62
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
63
# This currently does a kind of lazy conversion of file texts, where a
64
# new text is written in every version.  That's unnecessary but for
65
# the moment saves us having to worry about when files need new
66
# versions.
67
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
68
from cStringIO import StringIO
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
69
import os
1267 by Martin Pool
- notes on conversion of existing history to weaves
70
import tempfile
71
import sys
1534.4.14 by Robert Collins
Replace copy_tree with transport logic in upgreade.
72
from stat import *
1132 by Martin Pool
- fix up logging for history2weaves tool
73
1534.4.28 by Robert Collins
first cut at merge from integration.
74
import bzrlib
1185.65.29 by Robert Collins
Implement final review suggestions.
75
from bzrlib.branch import Branch
1429 by Robert Collins
merge in niemeyers prefixed-store patch
76
from bzrlib.branch import BZR_BRANCH_FORMAT_5, BZR_BRANCH_FORMAT_6
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
77
from bzrlib.branch import BzrBranchFormat, BzrBranchFormat4, BzrBranchFormat5, BzrBranchFormat6
78
from bzrlib.errors import NoSuchFile, UpgradeReadonly
1185.17.1 by Martin Pool
[pick] clear hashcache in format upgrade to avoid worrisome warning
79
import bzrlib.hashcache as hashcache
1534.4.28 by Robert Collins
first cut at merge from integration.
80
from bzrlib.lockable_files import LockableFiles
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
81
from bzrlib.osutils import sha_strings, sha_string, pathjoin, abspath
82
from bzrlib.ui import ui_factory
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
83
from bzrlib.store.text import TextStore
84
from bzrlib.store.weave import WeaveStore
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
85
from bzrlib.trace import mutter, note, warning
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
86
from bzrlib.transactions import PassThroughTransaction
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
87
from bzrlib.transport import get_transport
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
88
from bzrlib.transport.local import LocalTransport
1080 by Martin Pool
- test tool for converting history to weave files
89
from bzrlib.weave import Weave
90
from bzrlib.weavefile import read_weave, write_weave
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
91
from bzrlib.xml4 import serializer_v4
92
from bzrlib.xml5 import serializer_v5
1185.62.12 by John Arbash Meinel
Adding TODO to upgrade.py to remove ancestry.weave
93
94
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
95
class Convert(object):
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
96
97
    def __init__(self, transport):
98
        self.base = transport.base
1307 by Martin Pool
- start walking through ancestors in conversion to weaves
99
        self.converted_revs = set()
100
        self.absent_revisions = set()
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
101
        self.text_count = 0
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
102
        self.revisions = {}
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
103
        self.transport = transport
104
        if self.transport.is_readonly():
105
            raise UpgradeReadonly
1534.4.28 by Robert Collins
first cut at merge from integration.
106
        self.control_files = LockableFiles(transport.clone(bzrlib.BZRDIR), 'branch-lock')
107
        # Lock the branch (soon to be meta dir) to prevent anyone racing with us
108
        # This is currently windows incompatible, it will deadlock. When the upgrade
109
        # logic becomes format specific, then we can have the format know how to pass this
110
        # on. Also note that we probably have an 'upgrade meta' which upgrades the constituent
111
        # parts.
112
        print "FIXME: control files reuse" 
113
        self.control_files.lock_write()
114
        try:
115
            self.convert()
116
        finally:
117
            self.control_files.unlock()
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
118
119
    def convert(self):
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
120
        if not self._open_branch():
121
            return
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
122
        note('starting upgrade of %s', self.base)
1381 by Martin Pool
- remove tab characters (only)
123
        self._backup_control_dir()
1429 by Robert Collins
merge in niemeyers prefixed-store patch
124
        self.pb = ui_factory.progress_bar()
1534.4.8 by Robert Collins
Unfuck upgrade.
125
        if isinstance(self.old_format, BzrBranchFormat4):
1429 by Robert Collins
merge in niemeyers prefixed-store patch
126
            note('starting upgrade from format 4 to 5')
127
            self._convert_to_weaves()
1534.4.8 by Robert Collins
Unfuck upgrade.
128
        if isinstance(self.old_format, BzrBranchFormat5):
1429 by Robert Collins
merge in niemeyers prefixed-store patch
129
            note('starting upgrade from format 5 to 6')
130
            self._convert_to_prefixed()
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
131
        if isinstance(self.transport, LocalTransport):
132
            cache = hashcache.HashCache(abspath(self.base))
133
            cache.clear()
134
            cache.write()
1429 by Robert Collins
merge in niemeyers prefixed-store patch
135
        note("finished")
136
137
    def _convert_to_prefixed(self):
138
        from bzrlib.store import hash_prefix
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
139
        bzr_transport = self.transport.clone('.bzr')
140
        bzr_transport.delete('branch-format')
1429 by Robert Collins
merge in niemeyers prefixed-store patch
141
        for store_name in ["weaves", "revision-store"]:
142
            note("adding prefixes to %s" % store_name) 
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
143
            store_transport = bzr_transport.clone(store_name)
144
            for filename in store_transport.list_dir('.'):
1534.4.30 by Robert Collins
Test signature preservation on clone and upgrade.
145
                if (filename.endswith(".weave") or
146
                    filename.endswith(".gz") or
147
                    filename.endswith(".sig")):
1429 by Robert Collins
merge in niemeyers prefixed-store patch
148
                    file_id = os.path.splitext(filename)[0]
149
                else:
150
                    file_id = filename
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
151
                prefix_dir = hash_prefix(file_id)
152
                # FIXME keep track of the dirs made RBC 20060121
153
                try:
154
                    store_transport.move(filename, prefix_dir + '/' + filename)
155
                except NoSuchFile: # catches missing dirs strangely enough
156
                    store_transport.mkdir(prefix_dir)
157
                    store_transport.move(filename, prefix_dir + '/' + filename)
1429 by Robert Collins
merge in niemeyers prefixed-store patch
158
        self._set_new_format(BZR_BRANCH_FORMAT_6)
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
159
        self.branch = BzrBranchFormat6().open(self.transport)
160
        self.old_format = self.branch._branch_format
1429 by Robert Collins
merge in niemeyers prefixed-store patch
161
162
    def _convert_to_weaves(self):
1381 by Martin Pool
- remove tab characters (only)
163
        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
164
        bzr_transport = self.transport.clone('.bzr')
165
        try:
166
            # TODO permissions
167
            stat = bzr_transport.stat('weaves')
168
            if not S_ISDIR(stat.st_mode):
169
                bzr_transport.delete('weaves')
170
                bzr_transport.mkdir('weaves')
171
        except NoSuchFile:
172
            bzr_transport.mkdir('weaves')
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
173
        self.inv_weave = Weave('inventory')
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
174
        # holds in-memory weaves for all files
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
175
        self.text_weaves = {}
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
176
        bzr_transport.delete('branch-format')
1381 by Martin Pool
- remove tab characters (only)
177
        self._convert_working_inv()
1358 by Martin Pool
- actually upgrade all of history
178
        rev_history = self.branch.revision_history()
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
179
        # to_read is a stack holding the revisions we still need to process;
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
180
        # appending to it adds new highest-priority revisions
1319 by Martin Pool
- calculate and use file parents for importing texts
181
        self.known_revisions = set(rev_history)
1185.20.1 by Andres Salomon
Handle the case where revision_history() returns an empty list during
182
        self.to_read = rev_history[-1:]
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
183
        while self.to_read:
184
            rev_id = self.to_read.pop()
185
            if (rev_id not in self.revisions
186
                and rev_id not in self.absent_revisions):
187
                self._load_one_rev(rev_id)
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
188
        self.pb.clear()
1332 by Martin Pool
- clean up code that writes out weave results
189
        to_import = self._make_order()
1315 by Martin Pool
- import file inventories in correct order
190
        for i, rev_id in enumerate(to_import):
191
            self.pb.update('converting revision', i, len(to_import))
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
192
            self._convert_one_rev(rev_id)
1331 by Martin Pool
- write out new revisions after conversion
193
        self.pb.clear()
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
194
        self._write_all_weaves()
195
        self._write_all_revs()
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
196
        note('upgraded to weaves:')
197
        note('  %6d revisions and inventories' % len(self.revisions))
1393.1.44 by Martin Pool
- upgrade carries across ghost references
198
        note('  %6d revisions not present' % len(self.absent_revisions))
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
199
        note('  %6d texts' % self.text_count)
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
200
        self._cleanup_spare_files_after_format4()
1429 by Robert Collins
merge in niemeyers prefixed-store patch
201
        self._set_new_format(BZR_BRANCH_FORMAT_5)
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
202
        self.branch = BzrBranchFormat5().open(self.transport)
203
        self.old_format = self.branch._branch_format
1357 by Martin Pool
- require marker file to do upgrade so as not to clobber something important
204
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
205
    def _open_branch(self):
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
206
        self.old_format = BzrBranchFormat.find_format(self.transport)
207
        self.branch = self.old_format.open(self.transport)
1534.4.8 by Robert Collins
Unfuck upgrade.
208
        if isinstance(self.old_format, BzrBranchFormat6):
209
            note('this branch is in the most current format (%s)', self.old_format)
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
210
            return False
1534.4.8 by Robert Collins
Unfuck upgrade.
211
        if (not isinstance(self.old_format, BzrBranchFormat4) and
212
            not isinstance(self.old_format, BzrBranchFormat5)):
213
            raise BzrError("cannot upgrade from branch format %s" %
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
214
                           self.branch._branch_format)
215
        return True
216
1429 by Robert Collins
merge in niemeyers prefixed-store patch
217
    def _set_new_format(self, format):
1185.65.12 by Robert Collins
Remove the only-used-once put_controlfiles, and change put_controlfile to put and put_utf8.
218
        self.branch.control_files.put_utf8('branch-format', format)
1355 by Martin Pool
- write working inventory into final location
219
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
220
    def _cleanup_spare_files_after_format4(self):
221
        transport = self.transport.clone('.bzr')
1534.4.28 by Robert Collins
first cut at merge from integration.
222
        print "FIXME working tree upgrade foo."
1381 by Martin Pool
- remove tab characters (only)
223
        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.
224
            try:
225
                ## assert os.path.getsize(p) == 0
226
                transport.delete(n)
227
            except NoSuchFile:
228
                pass
229
        transport.delete_tree('inventory-store')
230
        transport.delete_tree('text-store')
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
231
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
232
    def _backup_control_dir(self):
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
233
        note('making backup of tree history')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
234
        self.transport.copy_tree('.bzr', '.bzr.backup')
235
        note('%s.bzr has been backed up to %s.bzr.backup',
236
             self.transport.base,
237
             self.transport.base)
1381 by Martin Pool
- remove tab characters (only)
238
        note('if conversion fails, you can move this directory back to .bzr')
239
        note('if it succeeds, you can remove this directory if you wish')
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
240
241
    def _convert_working_inv(self):
1381 by Martin Pool
- remove tab characters (only)
242
        branch = self.branch
1185.65.29 by Robert Collins
Implement final review suggestions.
243
        inv = serializer_v4.read_inventory(branch.control_files.get('inventory'))
1393.1.18 by Martin Pool
- fix upgrade for transport changes
244
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1534.4.28 by Robert Collins
first cut at merge from integration.
245
        print "fixme inventory is a working tree change."
1185.65.29 by Robert Collins
Implement final review suggestions.
246
        branch.control_files.put('inventory', new_inv_xml)
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
247
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
248
    def _write_all_weaves(self):
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
249
        bzr_transport = self.transport.clone('.bzr')
250
        controlweaves = WeaveStore(bzr_transport, prefixed=False)
251
        weave_transport = bzr_transport.clone('weaves')
252
        weaves = WeaveStore(weave_transport, prefixed=False)
253
        transaction = PassThroughTransaction()
254
255
        controlweaves.put_weave('inventory', self.inv_weave, transaction)
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
256
        i = 0
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
257
        try:
258
            for file_id, file_weave in self.text_weaves.items():
259
                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
260
                weaves.put_weave(file_id, file_weave, transaction)
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
261
                i += 1
262
        finally:
263
            self.pb.clear()
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
264
1331 by Martin Pool
- write out new revisions after conversion
265
    def _write_all_revs(self):
266
        """Write all revisions out in new form."""
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
267
        transport = self.transport.clone('.bzr')
268
        transport.delete_tree('revision-store')
269
        transport.mkdir('revision-store')
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
270
        revision_transport = transport.clone('revision-store')
271
        # TODO permissions
272
        revision_store = TextStore(revision_transport,
273
                                   prefixed=False,
274
                                   compressed=True)
1331 by Martin Pool
- write out new revisions after conversion
275
        try:
276
            for i, rev_id in enumerate(self.converted_revs):
277
                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
278
                rev_tmp = StringIO()
279
                serializer_v5.write_revision(self.revisions[rev_id], rev_tmp)
280
                rev_tmp.seek(0)
281
                revision_store.add(rev_tmp, rev_id)
1331 by Martin Pool
- write out new revisions after conversion
282
        finally:
283
            self.pb.clear()
1332 by Martin Pool
- clean up code that writes out weave results
284
1331 by Martin Pool
- write out new revisions after conversion
285
            
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
286
    def _load_one_rev(self, rev_id):
287
        """Load a revision object into memory.
288
289
        Any parents not either loaded or abandoned get queued to be
290
        loaded."""
291
        self.pb.update('loading revision',
1315 by Martin Pool
- import file inventories in correct order
292
                       len(self.revisions),
1319 by Martin Pool
- calculate and use file parents for importing texts
293
                       len(self.known_revisions))
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
294
        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
295
            self.pb.clear()
296
            note('revision {%s} not present in branch; '
1393.1.44 by Martin Pool
- upgrade carries across ghost references
297
                 'will be converted as a ghost',
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
298
                 rev_id)
299
            self.absent_revisions.add(rev_id)
300
        else:
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
301
            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
302
            rev = serializer_v4.read_revision_from_string(rev_xml)
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
303
            for parent_id in rev.parent_ids:
1319 by Martin Pool
- calculate and use file parents for importing texts
304
                self.known_revisions.add(parent_id)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
305
                self.to_read.append(parent_id)
306
            self.revisions[rev_id] = rev
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
307
308
309
    def _load_old_inventory(self, rev_id):
310
        assert rev_id not in self.converted_revs
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
311
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
312
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
313
        rev = self.revisions[rev_id]
314
        if rev.inventory_sha1:
315
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
316
                'inventory sha mismatch for {%s}' % rev_id
317
        return inv
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
318
        
319
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
320
    def _load_updated_inventory(self, rev_id):
321
        assert rev_id in self.converted_revs
322
        inv_xml = self.inv_weave.get_text(rev_id)
323
        inv = serializer_v5.read_inventory_from_string(inv_xml)
324
        return inv
325
326
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
327
    def _convert_one_rev(self, rev_id):
328
        """Convert revision and all referenced objects to new format."""
329
        rev = self.revisions[rev_id]
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
330
        inv = self._load_old_inventory(rev_id)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
331
        present_parents = [p for p in rev.parent_ids
332
                           if p not in self.absent_revisions]
333
        self._convert_revision_contents(rev, inv, present_parents)
334
        self._store_new_weave(rev, inv, present_parents)
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
335
        self.converted_revs.add(rev_id)
336
337
1393.1.44 by Martin Pool
- upgrade carries across ghost references
338
    def _store_new_weave(self, rev, inv, present_parents):
1320 by Martin Pool
- write updated inventory into weave
339
        # the XML is now updated with text versions
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
340
        if __debug__:
341
            for file_id in inv:
342
                ie = inv[file_id]
343
                if ie.kind == 'root_directory':
344
                    continue
1092.2.21 by Robert Collins
convert name_version to revision in inventory entries
345
                assert hasattr(ie, 'revision'), \
346
                    'no revision on {%s} in {%s}' % \
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
347
                    (file_id, rev.revision_id)
1316 by Martin Pool
- upgrade format of inventories as they're converted
348
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1325 by Martin Pool
- conversion to weave tries to avoid repeated SHA calculation
349
        new_inv_sha1 = sha_string(new_inv_xml)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
350
        self.inv_weave.add(rev.revision_id, 
351
                           present_parents,
1325 by Martin Pool
- conversion to weave tries to avoid repeated SHA calculation
352
                           new_inv_xml.splitlines(True),
353
                           new_inv_sha1)
354
        rev.inventory_sha1 = new_inv_sha1
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
355
1393.1.44 by Martin Pool
- upgrade carries across ghost references
356
    def _convert_revision_contents(self, rev, inv, present_parents):
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
357
        """Convert all the files within a revision.
358
359
        Also upgrade the inventory to refer to the text revision ids."""
360
        rev_id = rev.revision_id
1319 by Martin Pool
- calculate and use file parents for importing texts
361
        mutter('converting texts of revision {%s}',
362
               rev_id)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
363
        parent_invs = map(self._load_updated_inventory, present_parents)
1332 by Martin Pool
- clean up code that writes out weave results
364
        for file_id in inv:
365
            ie = inv[file_id]
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
366
            self._convert_file_version(rev, ie, parent_invs)
367
368
    def _convert_file_version(self, rev, ie, parent_invs):
1319 by Martin Pool
- calculate and use file parents for importing texts
369
        """Convert one version of one file.
370
371
        The file needs to be added into the weave if it is a merge
372
        of >=2 parents or if it's changed from its parent.
373
        """
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
374
        if ie.kind == 'root_directory':
375
            return
1319 by Martin Pool
- calculate and use file parents for importing texts
376
        file_id = ie.file_id
377
        rev_id = rev.revision_id
378
        w = self.text_weaves.get(file_id)
379
        if w is None:
380
            w = Weave(file_id)
381
            self.text_weaves[file_id] = w
382
        text_changed = False
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
383
        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
384
        for old_revision in previous_entries:
1092.2.22 by Robert Collins
text_version and name_version unification looking reasonable
385
                # if this fails, its a ghost ?
386
                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
387
        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
388
        del ie.text_id
389
        assert getattr(ie, 'revision', None) is not None
390
391
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
392
        # TODO: convert this logic, which is ~= snapshot to
393
        # 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
394
        # a v4 revision_tree can be given, or something that looks enough like
395
        # 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
396
        # and we need something that looks like a weave store for snapshot to 
397
        # save against.
398
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
399
        if len(previous_revisions) == 1:
400
            previous_ie = previous_revisions.values()[0]
401
            if ie._unchanged(previous_ie):
402
                ie.revision = previous_ie.revision
403
                return
404
        parent_indexes = map(w.lookup, previous_revisions)
405
        if ie.has_text():
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
406
            text = self.branch.repository.text_store.get(ie.text_id)
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
407
            file_lines = text.readlines()
1378 by Martin Pool
- in upgrade, avoiding loading file texts unless necessary
408
            assert sha_strings(file_lines) == ie.text_sha1
409
            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
410
            w.add(rev_id, parent_indexes, file_lines, ie.text_sha1)
1332 by Martin Pool
- clean up code that writes out weave results
411
            self.text_count += 1
1319 by Martin Pool
- calculate and use file parents for importing texts
412
        else:
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
413
            w.add(rev_id, parent_indexes, [], None)
414
        ie.revision = rev_id
415
        ##mutter('import text {%s} of {%s}',
416
        ##       ie.text_id, file_id)
1310 by Martin Pool
- compute order to import revisions
417
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
418
    def _make_order(self):
1310 by Martin Pool
- compute order to import revisions
419
        """Return a suitable order for importing revisions.
420
421
        The order must be such that an revision is imported after all
422
        its (present) parents.
423
        """
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
424
        todo = set(self.revisions.keys())
425
        done = self.absent_revisions.copy()
1310 by Martin Pool
- compute order to import revisions
426
        o = []
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
427
        while todo:
428
            # scan through looking for a revision whose parents
429
            # are all done
1310 by Martin Pool
- compute order to import revisions
430
            for rev_id in sorted(list(todo)):
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
431
                rev = self.revisions[rev_id]
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
432
                parent_ids = set(rev.parent_ids)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
433
                if parent_ids.issubset(done):
434
                    # can take this one now
1310 by Martin Pool
- compute order to import revisions
435
                    o.append(rev_id)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
436
                    todo.remove(rev_id)
437
                    done.add(rev_id)
1315 by Martin Pool
- import file inventories in correct order
438
        return o
1377 by Martin Pool
- run conversion to weaves from the 'bzr upgrade' command
439
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
440
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
441
def upgrade(url):
442
    t = get_transport(url)
443
    Convert(t)