/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
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
1429 by Robert Collins
merge in niemeyers prefixed-store patch
74
from bzrlib.branch import Branch, find_branch
75
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
76
from bzrlib.branch import BzrBranchFormat, BzrBranchFormat4, BzrBranchFormat5, BzrBranchFormat6
77
from bzrlib.errors import NoSuchFile, UpgradeReadonly
1185.17.1 by Martin Pool
[pick] clear hashcache in format upgrade to avoid worrisome warning
78
import bzrlib.hashcache as hashcache
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
79
from bzrlib.osutils import sha_strings, sha_string, pathjoin, abspath
80
from bzrlib.ui import ui_factory
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
81
from bzrlib.store.text import TextStore
82
from bzrlib.store.weave import WeaveStore
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
83
from bzrlib.trace import mutter, note, warning
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
84
from bzrlib.transactions import PassThroughTransaction
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
85
from bzrlib.transport import get_transport
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
86
from bzrlib.transport.local import LocalTransport
1080 by Martin Pool
- test tool for converting history to weave files
87
from bzrlib.weave import Weave
88
from bzrlib.weavefile import read_weave, write_weave
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
89
from bzrlib.xml4 import serializer_v4
90
from bzrlib.xml5 import serializer_v5
1185.62.12 by John Arbash Meinel
Adding TODO to upgrade.py to remove ancestry.weave
91
92
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
93
class Convert(object):
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
94
95
    def __init__(self, transport):
96
        self.base = transport.base
1307 by Martin Pool
- start walking through ancestors in conversion to weaves
97
        self.converted_revs = set()
98
        self.absent_revisions = set()
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
99
        self.text_count = 0
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
100
        self.revisions = {}
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
101
        self.transport = transport
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
102
        self.convert()
103
104
    def convert(self):
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
105
        if self.transport.is_readonly():
106
            raise UpgradeReadonly
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
107
        if not self._open_branch():
108
            return
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
109
        note('starting upgrade of %s', self.base)
1381 by Martin Pool
- remove tab characters (only)
110
        self._backup_control_dir()
1429 by Robert Collins
merge in niemeyers prefixed-store patch
111
        self.pb = ui_factory.progress_bar()
1534.4.8 by Robert Collins
Unfuck upgrade.
112
        if isinstance(self.old_format, BzrBranchFormat4):
1429 by Robert Collins
merge in niemeyers prefixed-store patch
113
            note('starting upgrade from format 4 to 5')
114
            self._convert_to_weaves()
1534.4.8 by Robert Collins
Unfuck upgrade.
115
        if isinstance(self.old_format, BzrBranchFormat5):
1429 by Robert Collins
merge in niemeyers prefixed-store patch
116
            note('starting upgrade from format 5 to 6')
117
            self._convert_to_prefixed()
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
118
        if isinstance(self.transport, LocalTransport):
119
            cache = hashcache.HashCache(abspath(self.base))
120
            cache.clear()
121
            cache.write()
1429 by Robert Collins
merge in niemeyers prefixed-store patch
122
        note("finished")
123
124
    def _convert_to_prefixed(self):
125
        from bzrlib.store import hash_prefix
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
126
        bzr_transport = self.transport.clone('.bzr')
127
        bzr_transport.delete('branch-format')
1429 by Robert Collins
merge in niemeyers prefixed-store patch
128
        for store_name in ["weaves", "revision-store"]:
129
            note("adding prefixes to %s" % store_name) 
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
130
            store_transport = bzr_transport.clone(store_name)
131
            for filename in store_transport.list_dir('.'):
1429 by Robert Collins
merge in niemeyers prefixed-store patch
132
                if filename.endswith(".weave") or filename.endswith(".gz"):
133
                    file_id = os.path.splitext(filename)[0]
134
                else:
135
                    file_id = filename
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
136
                prefix_dir = hash_prefix(file_id)
137
                # FIXME keep track of the dirs made RBC 20060121
138
                try:
139
                    store_transport.move(filename, prefix_dir + '/' + filename)
140
                except NoSuchFile: # catches missing dirs strangely enough
141
                    store_transport.mkdir(prefix_dir)
142
                    store_transport.move(filename, prefix_dir + '/' + filename)
1429 by Robert Collins
merge in niemeyers prefixed-store patch
143
        self._set_new_format(BZR_BRANCH_FORMAT_6)
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
144
        self.branch = BzrBranchFormat6().open(self.transport)
145
        self.old_format = self.branch._branch_format
1429 by Robert Collins
merge in niemeyers prefixed-store patch
146
147
    def _convert_to_weaves(self):
1381 by Martin Pool
- remove tab characters (only)
148
        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
149
        bzr_transport = self.transport.clone('.bzr')
150
        try:
151
            # TODO permissions
152
            stat = bzr_transport.stat('weaves')
153
            if not S_ISDIR(stat.st_mode):
154
                bzr_transport.delete('weaves')
155
                bzr_transport.mkdir('weaves')
156
        except NoSuchFile:
157
            bzr_transport.mkdir('weaves')
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
158
        self.inv_weave = Weave('inventory')
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
159
        # holds in-memory weaves for all files
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
160
        self.text_weaves = {}
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
161
        bzr_transport.delete('branch-format')
1381 by Martin Pool
- remove tab characters (only)
162
        self._convert_working_inv()
1358 by Martin Pool
- actually upgrade all of history
163
        rev_history = self.branch.revision_history()
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
164
        # to_read is a stack holding the revisions we still need to process;
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
165
        # appending to it adds new highest-priority revisions
1319 by Martin Pool
- calculate and use file parents for importing texts
166
        self.known_revisions = set(rev_history)
1185.20.1 by Andres Salomon
Handle the case where revision_history() returns an empty list during
167
        self.to_read = rev_history[-1:]
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
168
        while self.to_read:
169
            rev_id = self.to_read.pop()
170
            if (rev_id not in self.revisions
171
                and rev_id not in self.absent_revisions):
172
                self._load_one_rev(rev_id)
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
173
        self.pb.clear()
1332 by Martin Pool
- clean up code that writes out weave results
174
        to_import = self._make_order()
1315 by Martin Pool
- import file inventories in correct order
175
        for i, rev_id in enumerate(to_import):
176
            self.pb.update('converting revision', i, len(to_import))
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
177
            self._convert_one_rev(rev_id)
1331 by Martin Pool
- write out new revisions after conversion
178
        self.pb.clear()
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
179
        self._write_all_weaves()
180
        self._write_all_revs()
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
181
        note('upgraded to weaves:')
182
        note('  %6d revisions and inventories' % len(self.revisions))
1393.1.44 by Martin Pool
- upgrade carries across ghost references
183
        note('  %6d revisions not present' % len(self.absent_revisions))
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
184
        note('  %6d texts' % self.text_count)
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
185
        self._cleanup_spare_files_after_format4()
1429 by Robert Collins
merge in niemeyers prefixed-store patch
186
        self._set_new_format(BZR_BRANCH_FORMAT_5)
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
187
        self.branch = BzrBranchFormat5().open(self.transport)
188
        self.old_format = self.branch._branch_format
1357 by Martin Pool
- require marker file to do upgrade so as not to clobber something important
189
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
190
    def _open_branch(self):
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
191
        self.old_format = BzrBranchFormat.find_format(self.transport)
192
        self.branch = self.old_format.open(self.transport)
1534.4.8 by Robert Collins
Unfuck upgrade.
193
        if isinstance(self.old_format, BzrBranchFormat6):
194
            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
195
            return False
1534.4.8 by Robert Collins
Unfuck upgrade.
196
        if (not isinstance(self.old_format, BzrBranchFormat4) and
197
            not isinstance(self.old_format, BzrBranchFormat5)):
198
            raise BzrError("cannot upgrade from branch format %s" %
1382 by Martin Pool
- upgrade checks if branch is uptodate before anything else
199
                           self.branch._branch_format)
200
        return True
201
1429 by Robert Collins
merge in niemeyers prefixed-store patch
202
    def _set_new_format(self, format):
203
        self.branch.put_controlfile('branch-format', format)
1355 by Martin Pool
- write working inventory into final location
204
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
205
    def _cleanup_spare_files_after_format4(self):
206
        transport = self.transport.clone('.bzr')
1381 by Martin Pool
- remove tab characters (only)
207
        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.
208
            try:
209
                ## assert os.path.getsize(p) == 0
210
                transport.delete(n)
211
            except NoSuchFile:
212
                pass
213
        transport.delete_tree('inventory-store')
214
        transport.delete_tree('text-store')
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
215
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
216
    def _backup_control_dir(self):
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
217
        note('making backup of tree history')
1534.4.14 by Robert Collins
Replace copy_tree with transport logic in upgreade.
218
        source = self.transport.clone('.bzr')
219
        self.transport.mkdir('.bzr.backup')
220
        backup = self.transport.clone('.bzr.backup')
221
        files = []
222
        directories = ['.']
223
        while directories:
224
            dir = directories.pop()
225
            if dir != '.':
226
                backup.mkdir(dir)
227
            for path in source.list_dir(dir):
228
                path = dir + '/' + path
229
                stat = source.stat(path)
230
                if S_ISDIR(stat.st_mode):
231
                    directories.append(path)
232
                else:
233
                    files.append(path)
234
        source.copy_to(files, backup)
235
        note('%s has been backed up to %s', source.base, backup.base)
1381 by Martin Pool
- remove tab characters (only)
236
        note('if conversion fails, you can move this directory back to .bzr')
237
        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
238
239
    def _convert_working_inv(self):
1381 by Martin Pool
- remove tab characters (only)
240
        branch = self.branch
241
        inv = serializer_v4.read_inventory(branch.controlfile('inventory', 'rb'))
1393.1.18 by Martin Pool
- fix upgrade for transport changes
242
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
243
        branch.put_controlfile('inventory', new_inv_xml)
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
244
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
245
    def _write_all_weaves(self):
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
246
        bzr_transport = self.transport.clone('.bzr')
247
        controlweaves = WeaveStore(bzr_transport, prefixed=False)
248
        weave_transport = bzr_transport.clone('weaves')
249
        weaves = WeaveStore(weave_transport, prefixed=False)
250
        transaction = PassThroughTransaction()
251
252
        controlweaves.put_weave('inventory', self.inv_weave, transaction)
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
253
        i = 0
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
254
        try:
255
            for file_id, file_weave in self.text_weaves.items():
256
                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
257
                weaves.put_weave(file_id, file_weave, transaction)
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
258
                i += 1
259
        finally:
260
            self.pb.clear()
1300 by Martin Pool
- refactor weave upgrade into a MethodObject
261
1331 by Martin Pool
- write out new revisions after conversion
262
    def _write_all_revs(self):
263
        """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.
264
        transport = self.transport.clone('.bzr')
265
        transport.delete_tree('revision-store')
266
        transport.mkdir('revision-store')
1534.4.16 by Robert Collins
Last vestiges of local file requirements for upgrade nuked
267
        revision_transport = transport.clone('revision-store')
268
        # TODO permissions
269
        revision_store = TextStore(revision_transport,
270
                                   prefixed=False,
271
                                   compressed=True)
1331 by Martin Pool
- write out new revisions after conversion
272
        try:
273
            for i, rev_id in enumerate(self.converted_revs):
274
                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
275
                rev_tmp = StringIO()
276
                serializer_v5.write_revision(self.revisions[rev_id], rev_tmp)
277
                rev_tmp.seek(0)
278
                revision_store.add(rev_tmp, rev_id)
1331 by Martin Pool
- write out new revisions after conversion
279
        finally:
280
            self.pb.clear()
1332 by Martin Pool
- clean up code that writes out weave results
281
1331 by Martin Pool
- write out new revisions after conversion
282
            
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
283
    def _load_one_rev(self, rev_id):
284
        """Load a revision object into memory.
285
286
        Any parents not either loaded or abandoned get queued to be
287
        loaded."""
288
        self.pb.update('loading revision',
1315 by Martin Pool
- import file inventories in correct order
289
                       len(self.revisions),
1319 by Martin Pool
- calculate and use file parents for importing texts
290
                       len(self.known_revisions))
1442.1.45 by Robert Collins
replace __contains__ calls in stores with has_id
291
        if not self.branch.revision_store.has_id(rev_id):
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
292
            self.pb.clear()
293
            note('revision {%s} not present in branch; '
1393.1.44 by Martin Pool
- upgrade carries across ghost references
294
                 'will be converted as a ghost',
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
295
                 rev_id)
296
            self.absent_revisions.add(rev_id)
297
        else:
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
298
            rev_xml = self.branch.revision_store.get(rev_id).read()
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
299
            rev = serializer_v4.read_revision_from_string(rev_xml)
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
300
            for parent_id in rev.parent_ids:
1319 by Martin Pool
- calculate and use file parents for importing texts
301
                self.known_revisions.add(parent_id)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
302
                self.to_read.append(parent_id)
303
            self.revisions[rev_id] = rev
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
304
305
306
    def _load_old_inventory(self, rev_id):
307
        assert rev_id not in self.converted_revs
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
308
        old_inv_xml = self.branch.inventory_store.get(rev_id).read()
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
309
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
310
        rev = self.revisions[rev_id]
311
        if rev.inventory_sha1:
312
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
313
                'inventory sha mismatch for {%s}' % rev_id
314
        return inv
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
315
        
316
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
317
    def _load_updated_inventory(self, rev_id):
318
        assert rev_id in self.converted_revs
319
        inv_xml = self.inv_weave.get_text(rev_id)
320
        inv = serializer_v5.read_inventory_from_string(inv_xml)
321
        return inv
322
323
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
324
    def _convert_one_rev(self, rev_id):
325
        """Convert revision and all referenced objects to new format."""
326
        rev = self.revisions[rev_id]
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
327
        inv = self._load_old_inventory(rev_id)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
328
        present_parents = [p for p in rev.parent_ids
329
                           if p not in self.absent_revisions]
330
        self._convert_revision_contents(rev, inv, present_parents)
331
        self._store_new_weave(rev, inv, present_parents)
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
332
        self.converted_revs.add(rev_id)
333
334
1393.1.44 by Martin Pool
- upgrade carries across ghost references
335
    def _store_new_weave(self, rev, inv, present_parents):
1320 by Martin Pool
- write updated inventory into weave
336
        # the XML is now updated with text versions
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
337
        if __debug__:
338
            for file_id in inv:
339
                ie = inv[file_id]
340
                if ie.kind == 'root_directory':
341
                    continue
1092.2.21 by Robert Collins
convert name_version to revision in inventory entries
342
                assert hasattr(ie, 'revision'), \
343
                    'no revision on {%s} in {%s}' % \
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
344
                    (file_id, rev.revision_id)
1316 by Martin Pool
- upgrade format of inventories as they're converted
345
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
1325 by Martin Pool
- conversion to weave tries to avoid repeated SHA calculation
346
        new_inv_sha1 = sha_string(new_inv_xml)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
347
        self.inv_weave.add(rev.revision_id, 
348
                           present_parents,
1325 by Martin Pool
- conversion to weave tries to avoid repeated SHA calculation
349
                           new_inv_xml.splitlines(True),
350
                           new_inv_sha1)
351
        rev.inventory_sha1 = new_inv_sha1
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
352
1393.1.44 by Martin Pool
- upgrade carries across ghost references
353
    def _convert_revision_contents(self, rev, inv, present_parents):
1318 by Martin Pool
- pull texts into weaves in a fairly lazy way
354
        """Convert all the files within a revision.
355
356
        Also upgrade the inventory to refer to the text revision ids."""
357
        rev_id = rev.revision_id
1319 by Martin Pool
- calculate and use file parents for importing texts
358
        mutter('converting texts of revision {%s}',
359
               rev_id)
1393.1.44 by Martin Pool
- upgrade carries across ghost references
360
        parent_invs = map(self._load_updated_inventory, present_parents)
1332 by Martin Pool
- clean up code that writes out weave results
361
        for file_id in inv:
362
            ie = inv[file_id]
1386 by Martin Pool
- avoiding loading all inventories upfront for conversion
363
            self._convert_file_version(rev, ie, parent_invs)
364
365
    def _convert_file_version(self, rev, ie, parent_invs):
1319 by Martin Pool
- calculate and use file parents for importing texts
366
        """Convert one version of one file.
367
368
        The file needs to be added into the weave if it is a merge
369
        of >=2 parents or if it's changed from its parent.
370
        """
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
371
        if ie.kind == 'root_directory':
372
            return
1319 by Martin Pool
- calculate and use file parents for importing texts
373
        file_id = ie.file_id
374
        rev_id = rev.revision_id
375
        w = self.text_weaves.get(file_id)
376
        if w is None:
377
            w = Weave(file_id)
378
            self.text_weaves[file_id] = w
379
        text_changed = False
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
380
        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
381
        for old_revision in previous_entries:
1092.2.22 by Robert Collins
text_version and name_version unification looking reasonable
382
                # if this fails, its a ghost ?
383
                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
384
        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
385
        del ie.text_id
386
        assert getattr(ie, 'revision', None) is not None
387
388
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
389
        # TODO: convert this logic, which is ~= snapshot to
390
        # 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
391
        # a v4 revision_tree can be given, or something that looks enough like
392
        # 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
393
        # and we need something that looks like a weave store for snapshot to 
394
        # save against.
395
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
396
        if len(previous_revisions) == 1:
397
            previous_ie = previous_revisions.values()[0]
398
            if ie._unchanged(previous_ie):
399
                ie.revision = previous_ie.revision
400
                return
401
        parent_indexes = map(w.lookup, previous_revisions)
402
        if ie.has_text():
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
403
            file_lines = self.branch.text_store.get(ie.text_id).readlines()
1378 by Martin Pool
- in upgrade, avoiding loading file texts unless necessary
404
            assert sha_strings(file_lines) == ie.text_sha1
405
            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
406
            w.add(rev_id, parent_indexes, file_lines, ie.text_sha1)
1332 by Martin Pool
- clean up code that writes out weave results
407
            self.text_count += 1
1319 by Martin Pool
- calculate and use file parents for importing texts
408
        else:
1405 by Robert Collins
remove some of the upgrade code that was duplicated with inventory_entry, and give all inventory entries a weave
409
            w.add(rev_id, parent_indexes, [], None)
410
        ie.revision = rev_id
411
        ##mutter('import text {%s} of {%s}',
412
        ##       ie.text_id, file_id)
1310 by Martin Pool
- compute order to import revisions
413
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
414
    def _make_order(self):
1310 by Martin Pool
- compute order to import revisions
415
        """Return a suitable order for importing revisions.
416
417
        The order must be such that an revision is imported after all
418
        its (present) parents.
419
        """
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
420
        todo = set(self.revisions.keys())
421
        done = self.absent_revisions.copy()
1310 by Martin Pool
- compute order to import revisions
422
        o = []
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
423
        while todo:
424
            # scan through looking for a revision whose parents
425
            # are all done
1310 by Martin Pool
- compute order to import revisions
426
            for rev_id in sorted(list(todo)):
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
427
                rev = self.revisions[rev_id]
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
428
                parent_ids = set(rev.parent_ids)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
429
                if parent_ids.issubset(done):
430
                    # can take this one now
1310 by Martin Pool
- compute order to import revisions
431
                    o.append(rev_id)
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
432
                    todo.remove(rev_id)
433
                    done.add(rev_id)
1315 by Martin Pool
- import file inventories in correct order
434
        return o
1377 by Martin Pool
- run conversion to weaves from the 'bzr upgrade' command
435
1309 by Martin Pool
- first cut at tsort to make order to bring in revisions
436
1534.4.13 by Robert Collins
Give a reasonable warning on attempts to upgrade a readonly url.
437
def upgrade(url):
438
    t = get_transport(url)
439
    Convert(t)