~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/serializer/v08.py

  • Committer: Martin Pool
  • Date: 2010-01-29 10:36:23 UTC
  • mto: This revision was merged to the branch mainline in revision 4992.
  • Revision ID: mbp@sourcefrog.net-20100129103623-hywka5hymo5z13jw
Change url to canonical.com or wiki, plus some doc improvements in passing

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Serializer factory for reading and writing bundles.
18
18
"""
19
19
 
20
20
import os
21
21
 
22
 
from bzrlib import errors
 
22
from bzrlib import (
 
23
    errors,
 
24
    ui,
 
25
    )
23
26
from bzrlib.bundle.serializer import (BundleSerializer,
24
 
                                      BUNDLE_HEADER,
 
27
                                      _get_bundle_header,
25
28
                                     )
26
29
from bzrlib.bundle.serializer import binary_diff
27
30
from bzrlib.bundle.bundle_data import (RevisionInfo, BundleInfo, BundleTree)
28
31
from bzrlib.diff import internal_diff
29
32
from bzrlib.osutils import pathjoin
30
 
from bzrlib.progress import DummyProgress
31
33
from bzrlib.revision import NULL_REVISION
32
 
import bzrlib.ui
33
34
from bzrlib.testament import StrictTestament
34
35
from bzrlib.timestamp import (
35
36
    format_highres_date,
119
120
        source.lock_read()
120
121
        try:
121
122
            self._write_main_header()
122
 
            pb = DummyProgress()
 
123
            pb = ui.ui_factory.nested_progress_bar()
123
124
            try:
124
125
                self._write_revisions(pb)
125
126
            finally:
126
 
                pass
127
 
                #pb.finished()
 
127
                pb.finished()
128
128
        finally:
129
129
            source.unlock()
130
130
 
 
131
    def write_bundle(self, repository, target, base, fileobj):
 
132
        return self._write_bundle(repository, target, base, fileobj)
 
133
 
131
134
    def _write_main_header(self):
132
135
        """Write the header for the changes"""
133
136
        f = self.to_file
134
 
        f.write(BUNDLE_HEADER)
135
 
        f.write('0.8\n')
 
137
        f.write(_get_bundle_header('0.8'))
136
138
        f.write('#\n')
137
139
 
138
 
    def _write(self, key, value, indent=1):
139
 
        """Write out meta information, with proper indenting, etc"""
140
 
        assert indent > 0, 'indentation must be greater than 0'
 
140
    def _write(self, key, value, indent=1, trailing_space_when_empty=False):
 
141
        """Write out meta information, with proper indenting, etc.
 
142
 
 
143
        :param trailing_space_when_empty: To work around a bug in earlier
 
144
            bundle readers, when writing an empty property, we use "prop: \n"
 
145
            rather than writing "prop:\n".
 
146
            If this parameter is True, and value is the empty string, we will
 
147
            write an extra space.
 
148
        """
 
149
        if indent < 1:
 
150
            raise ValueError('indentation must be greater than 0')
141
151
        f = self.to_file
142
152
        f.write('#' + (' ' * indent))
143
153
        f.write(key.encode('utf-8'))
144
154
        if not value:
145
 
            f.write(':\n')
 
155
            if trailing_space_when_empty and value == '':
 
156
                f.write(': \n')
 
157
            else:
 
158
                f.write(':\n')
146
159
        elif isinstance(value, str):
147
160
            f.write(': ')
148
161
            f.write(value)
170
183
 
171
184
        i_max = len(self.revision_ids)
172
185
        for i, rev_id in enumerate(self.revision_ids):
173
 
            pb.update("Generating revsion data", i, i_max)
 
186
            pb.update("Generating revision data", i, i_max)
174
187
            rev = self.source.get_revision(rev_id)
175
188
            if rev_id == last_rev_id:
176
189
                rev_tree = last_rev_tree
193
206
            else:
194
207
                base_tree = self.source.revision_tree(base_id)
195
208
            force_binary = (i != 0)
196
 
            self._write_revision(rev, rev_tree, base_id, base_tree, 
 
209
            self._write_revision(rev, rev_tree, base_id, base_tree,
197
210
                                 explicit_base, force_binary)
198
211
 
199
212
            last_rev_id = base_id
200
213
            last_rev_tree = base_tree
201
214
 
202
215
    def _testament_sha1(self, revision_id):
203
 
        return StrictTestament.from_revision(self.source, 
 
216
        return StrictTestament.from_revision(self.source,
204
217
                                             revision_id).as_sha1()
205
218
 
206
 
    def _write_revision(self, rev, rev_tree, base_rev, base_tree, 
 
219
    def _write_revision(self, rev, rev_tree, base_rev, base_tree,
207
220
                        explicit_base, force_binary):
208
221
        """Write out the information for a revision."""
209
222
        def w(key, value):
225
238
            w('base id', base_rev)
226
239
        if rev.properties:
227
240
            self._write('properties', None, indent=1)
228
 
            for name, value in rev.properties.items():
229
 
                self._write(name, value, indent=3)
230
 
        
 
241
            for name, value in sorted(rev.properties.items()):
 
242
                self._write(name, value, indent=3,
 
243
                            trailing_space_when_empty=True)
 
244
 
231
245
        # Add an extra blank space at the end
232
246
        self.to_file.write('\n')
233
247
 
240
254
        self.to_file.write(' // '.join(p_texts).encode('utf-8'))
241
255
        self.to_file.write('\n')
242
256
 
243
 
    def _write_delta(self, new_tree, old_tree, default_revision_id, 
 
257
    def _write_delta(self, new_tree, old_tree, default_revision_id,
244
258
                     force_binary):
245
259
        """Write out the changes between the trees."""
246
260
        DEVNULL = '/dev/null'
263
277
                old_lines = tree_lines(old_tree, require_text=True)
264
278
                new_lines = tree_lines(new_tree, require_text=True)
265
279
                action.write(self.to_file)
266
 
                internal_diff(old_path, old_lines, new_path, new_lines, 
 
280
                internal_diff(old_path, old_lines, new_path, new_lines,
267
281
                              self.to_file)
268
282
            except errors.BinaryFile:
269
283
                old_lines = tree_lines(old_tree, require_text=False)
270
284
                new_lines = tree_lines(new_tree, require_text=False)
271
285
                action.add_property('encoding', 'base64')
272
286
                action.write(self.to_file)
273
 
                binary_diff(old_path, old_lines, new_path, new_lines, 
 
287
                binary_diff(old_path, old_lines, new_path, new_lines,
274
288
                            self.to_file)
275
289
 
276
290
        def finish_action(action, file_id, kind, meta_modified, text_modified,
294
308
 
295
309
        for path, file_id, kind in delta.added:
296
310
            action = Action('added', [kind, path], [('file-id', file_id)])
297
 
            meta_modified = (kind=='file' and 
 
311
            meta_modified = (kind=='file' and
298
312
                             new_tree.is_executable(file_id))
299
313
            finish_action(action, file_id, kind, meta_modified, True,
300
314
                          DEVNULL, path)
318
332
                continue
319
333
            old_rev = getattr(old_tree.inventory[ie.file_id], 'revision', None)
320
334
            if new_rev != old_rev:
321
 
                action = Action('modified', [ie.kind, 
 
335
                action = Action('modified', [ie.kind,
322
336
                                             new_tree.id2path(ie.file_id)])
323
337
                action.add_utf8_property('last-changed', ie.revision)
324
338
                action.write(self.to_file)
336
350
        object.__init__(self)
337
351
        self.from_file = iter(from_file)
338
352
        self._next_line = None
339
 
        
 
353
 
340
354
        self.info = self._get_info()
341
355
        # We put the actual inventory ids in the footer, so that the patch
342
356
        # is easier to read for humans.
447
461
        else:
448
462
            # What do we do with a key we don't recognize
449
463
            raise errors.MalformedHeader('Unknown Key: "%s"' % key)
450
 
    
 
464
 
451
465
    def _read_many(self, indent):
452
466
        """If a line ends with no entry, that means that it should be
453
467
        followed with multiple lines of values.
490
504
            elif line.startswith('... '):
491
505
                action += line[len('... '):-1].decode('utf-8')
492
506
 
493
 
            if (self._next_line is not None and 
 
507
            if (self._next_line is not None and
494
508
                self._next_line.startswith('===')):
495
509
                return action, lines, True
496
510
            elif self._next_line is None or self._next_line.startswith('#'):
502
516
                lines.append(line)
503
517
 
504
518
        return action, lines, False
505
 
            
 
519
 
506
520
    def _read_patches(self):
507
521
        do_continue = True
508
522
        revision_actions = []
510
524
            action, lines, do_continue = self._read_one_patch()
511
525
            if action is not None:
512
526
                revision_actions.append((action, lines))
513
 
        assert self.info.revisions[-1].tree_actions is None
 
527
        if self.info.revisions[-1].tree_actions is not None:
 
528
            raise AssertionError()
514
529
        self.info.revisions[-1].tree_actions = revision_actions
515
530
 
516
531
    def _read_footer(self):