~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-07-06 03:15:29 UTC
  • mfrom: (1711.2.78 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060706031529-e189d8c3f42076be
(jam) allow plugins to include benchmarks

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# (C) 2005 Canonical Development 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
19
19
 
20
20
import os
21
21
 
22
 
from bzrlib import errors
23
 
from bzrlib.bundle.serializer import (BundleSerializer,
24
 
                                      BUNDLE_HEADER,
 
22
from bzrlib.bundle.serializer import (BundleSerializer, 
 
23
                                      BUNDLE_HEADER, 
 
24
                                      format_highres_date,
 
25
                                      unpack_highres_date,
25
26
                                     )
26
27
from bzrlib.bundle.serializer import binary_diff
27
28
from bzrlib.bundle.bundle_data import (RevisionInfo, BundleInfo, BundleTree)
 
29
from bzrlib.delta import compare_trees
28
30
from bzrlib.diff import internal_diff
 
31
import bzrlib.errors as errors
29
32
from bzrlib.osutils import pathjoin
30
33
from bzrlib.progress import DummyProgress
31
34
from bzrlib.revision import NULL_REVISION
 
35
from bzrlib.rio import RioWriter, read_stanzas
32
36
import bzrlib.ui
33
37
from bzrlib.testament import StrictTestament
34
 
from bzrlib.timestamp import (
35
 
    format_highres_date,
36
 
    unpack_highres_date,
37
 
)
38
38
from bzrlib.textfile import text_file
39
39
from bzrlib.trace import mutter
40
40
 
55
55
        else:
56
56
            self.properties = properties
57
57
 
58
 
    def add_utf8_property(self, name, value):
59
 
        """Add a property whose value is currently utf8 to the action."""
60
 
        self.properties.append((name, value.decode('utf8')))
61
 
 
62
58
    def add_property(self, name, value):
63
59
        """Add a property to the action"""
64
60
        self.properties.append((name, value))
99
95
        """
100
96
        return BundleReader(f).info
101
97
 
102
 
    def check_compatible(self):
103
 
        if self.source.supports_rich_root():
104
 
            raise errors.IncompatibleBundleFormat('0.8', repr(self.source))
105
 
 
106
98
    def write(self, source, revision_ids, forced_bases, f):
107
99
        """Write the bundless to the supplied files.
108
100
 
115
107
        self.revision_ids = revision_ids
116
108
        self.forced_bases = forced_bases
117
109
        self.to_file = f
118
 
        self.check_compatible()
119
110
        source.lock_read()
120
111
        try:
121
112
            self._write_main_header()
135
126
        f.write('0.8\n')
136
127
        f.write('#\n')
137
128
 
138
 
    def _write(self, key, value, indent=1, trailing_space_when_empty=False):
139
 
        """Write out meta information, with proper indenting, etc.
140
 
 
141
 
        :param trailing_space_when_empty: To work around a bug in earlier
142
 
            bundle readers, when writing an empty property, we use "prop: \n"
143
 
            rather than writing "prop:\n".
144
 
            If this parameter is True, and value is the empty string, we will
145
 
            write an extra space.
146
 
        """
 
129
    def _write(self, key, value, indent=1):
 
130
        """Write out meta information, with proper indenting, etc"""
147
131
        assert indent > 0, 'indentation must be greater than 0'
148
132
        f = self.to_file
149
133
        f.write('#' + (' ' * indent))
150
134
        f.write(key.encode('utf-8'))
151
135
        if not value:
152
 
            if trailing_space_when_empty and value == '':
153
 
                f.write(': \n')
154
 
            else:
155
 
                f.write(':\n')
156
 
        elif isinstance(value, str):
157
 
            f.write(': ')
158
 
            f.write(value)
159
 
            f.write('\n')
160
 
        elif isinstance(value, unicode):
 
136
            f.write(':\n')
 
137
        elif isinstance(value, basestring):
161
138
            f.write(': ')
162
139
            f.write(value.encode('utf-8'))
163
140
            f.write('\n')
165
142
            f.write(':\n')
166
143
            for entry in value:
167
144
                f.write('#' + (' ' * (indent+2)))
168
 
                if isinstance(entry, str):
169
 
                    f.write(entry)
170
 
                else:
171
 
                    f.write(entry.encode('utf-8'))
 
145
                f.write(entry.encode('utf-8'))
172
146
                f.write('\n')
173
147
 
174
148
    def _write_revisions(self, pb):
178
152
        last_rev_id = None
179
153
        last_rev_tree = None
180
154
 
181
 
        i_max = len(self.revision_ids)
 
155
        i_max = len(self.revision_ids) 
182
156
        for i, rev_id in enumerate(self.revision_ids):
183
157
            pb.update("Generating revsion data", i, i_max)
184
158
            rev = self.source.get_revision(rev_id)
185
159
            if rev_id == last_rev_id:
186
160
                rev_tree = last_rev_tree
187
161
            else:
188
 
                rev_tree = self.source.revision_tree(rev_id)
 
162
                base_tree = self.source.revision_tree(rev_id)
 
163
            rev_tree = self.source.revision_tree(rev_id)
189
164
            if rev_id in self.forced_bases:
190
165
                explicit_base = True
191
166
                base_id = self.forced_bases[rev_id]
209
184
            last_rev_id = base_id
210
185
            last_rev_tree = base_tree
211
186
 
212
 
    def _testament_sha1(self, revision_id):
213
 
        return StrictTestament.from_revision(self.source, 
214
 
                                             revision_id).as_sha1()
215
 
 
216
187
    def _write_revision(self, rev, rev_tree, base_rev, base_tree, 
217
188
                        explicit_base, force_binary):
218
189
        """Write out the information for a revision."""
227
198
        self._write_delta(rev_tree, base_tree, rev.revision_id, force_binary)
228
199
 
229
200
        w('revision id', rev.revision_id)
230
 
        w('sha1', self._testament_sha1(rev.revision_id))
 
201
        w('sha1', StrictTestament.from_revision(self.source, 
 
202
                                                rev.revision_id).as_sha1())
231
203
        w('inventory sha1', rev.inventory_sha1)
232
204
        if rev.parent_ids:
233
205
            w('parent ids', rev.parent_ids)
235
207
            w('base id', base_rev)
236
208
        if rev.properties:
237
209
            self._write('properties', None, indent=1)
238
 
            for name, value in sorted(rev.properties.items()):
239
 
                self._write(name, value, indent=3,
240
 
                            trailing_space_when_empty=True)
 
210
            for name, value in rev.properties.items():
 
211
                self._write(name, value, indent=3)
241
212
        
242
213
        # Add an extra blank space at the end
243
214
        self.to_file.write('\n')
288
259
                          old_path, new_path):
289
260
            entry = new_tree.inventory[file_id]
290
261
            if entry.revision != default_revision_id:
291
 
                action.add_utf8_property('last-changed', entry.revision)
 
262
                action.add_property('last-changed', entry.revision)
292
263
            if meta_modified:
293
264
                action.add_bool_property('executable', entry.executable)
294
265
            if text_modified and kind == "symlink":
298
269
            else:
299
270
                action.write(self.to_file)
300
271
 
301
 
        delta = new_tree.changes_from(old_tree, want_unchanged=True,
302
 
                                      include_root=True)
 
272
        delta = compare_trees(old_tree, new_tree, want_unchanged=True)
303
273
        for path, file_id, kind in delta.removed:
304
274
            action = Action('removed', [kind, path]).write(self.to_file)
305
275
 
331
301
            if new_rev != old_rev:
332
302
                action = Action('modified', [ie.kind, 
333
303
                                             new_tree.id2path(ie.file_id)])
334
 
                action.add_utf8_property('last-changed', ie.revision)
 
304
                action.add_property('last-changed', ie.revision)
335
305
                action.write(self.to_file)
336
306
 
337
307
 
348
318
        self.from_file = iter(from_file)
349
319
        self._next_line = None
350
320
        
351
 
        self.info = self._get_info()
 
321
        self.info = BundleInfo()
352
322
        # We put the actual inventory ids in the footer, so that the patch
353
323
        # is easier to read for humans.
354
324
        # Unfortunately, that means we need to read everything before we
356
326
        self._read()
357
327
        self._validate()
358
328
 
359
 
    def _get_info(self):
360
 
        return BundleInfo08()
361
 
 
362
329
    def _read(self):
363
330
        self._next().next()
364
331
        while self._next_line is not None:
400
367
            # which does not start with '#'
401
368
            if line is None or line == '\n':
402
369
                break
403
 
            if not line.startswith('#'):
404
 
                continue
405
370
            found_something = True
406
371
            self._handle_next(line)
407
372
        if not found_something:
413
378
        """Read in a key-value pair
414
379
        """
415
380
        if not line.startswith('#'):
416
 
            raise errors.MalformedHeader('Bzr header did not start with #')
 
381
            raise MalformedHeader('Bzr header did not start with #')
417
382
        line = line[1:-1].decode('utf-8') # Remove the '#' and '\n'
418
383
        if line[:indent] == ' '*indent:
419
384
            line = line[indent:]
430
395
            key = line[:-1]
431
396
            value = self._read_many(indent=indent+2)
432
397
        else:
433
 
            raise errors.MalformedHeader('While looking for key: value pairs,'
 
398
            raise MalformedHeader('While looking for key: value pairs,'
434
399
                    ' did not find the colon %r' % (line))
435
400
 
436
401
        key = key.replace(' ', '_')
446
411
            return
447
412
 
448
413
        revision_info = self.info.revisions[-1]
449
 
        if key in revision_info.__dict__:
 
414
        if hasattr(revision_info, key):
450
415
            if getattr(revision_info, key) is None:
451
 
                if key in ('file_id', 'revision_id', 'base_id'):
452
 
                    value = value.encode('utf8')
453
 
                elif key in ('parent_ids'):
454
 
                    value = [v.encode('utf8') for v in value]
455
416
                setattr(revision_info, key, value)
456
417
            else:
457
 
                raise errors.MalformedHeader('Duplicated Key: %s' % key)
 
418
                raise MalformedHeader('Duplicated Key: %s' % key)
458
419
        else:
459
420
            # What do we do with a key we don't recognize
460
 
            raise errors.MalformedHeader('Unknown Key: "%s"' % key)
 
421
            raise MalformedHeader('Unknown Key: "%s"' % key)
461
422
    
462
423
    def _read_many(self, indent):
463
424
        """If a line ends with no entry, that means that it should be
494
455
        for line in self._next():
495
456
            if first:
496
457
                if not line.startswith('==='):
497
 
                    raise errors.MalformedPatches('The first line of all patches'
 
458
                    raise MalformedPatches('The first line of all patches'
498
459
                        ' should be a bzr meta line "==="'
499
460
                        ': %r' % line)
500
461
                action = line[4:-1].decode('utf-8')
532
493
        """
533
494
        for line in self._next():
534
495
            self._handle_next(line)
535
 
            if self._next_line is None:
536
 
                break
537
496
            if not self._next_line.startswith('#'):
538
 
                # Consume the trailing \n and stop processing
539
497
                self._next().next()
540
498
                break
541
 
 
542
 
class BundleInfo08(BundleInfo):
543
 
 
544
 
    def _update_tree(self, bundle_tree, revision_id):
545
 
        bundle_tree.note_last_changed('', revision_id)
546
 
        BundleInfo._update_tree(self, bundle_tree, revision_id)
547
 
 
548
 
    def _testament_sha1_from_revision(self, repository, revision_id):
549
 
        testament = StrictTestament.from_revision(repository, revision_id)
550
 
        return testament.as_sha1()
551
 
 
552
 
    def _testament_sha1(self, revision, inventory):
553
 
        return StrictTestament(revision, inventory).as_sha1()
 
499
            if self._next_line is None:
 
500
                break