/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to brzlib/bundle/bundle_data.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-21 12:41:27 UTC
  • mto: This revision was merged to the branch mainline in revision 6623.
  • Revision ID: jelmer@jelmer.uk-20170521124127-iv8etg0vwymyai6y
s/bzr/brz/ in apport config.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Read in a bundle stream, and process it into a BundleReader object."""
18
18
 
 
19
from __future__ import absolute_import
 
20
 
19
21
import base64
20
 
from io import BytesIO
 
22
from cStringIO import StringIO
21
23
import os
22
24
import pprint
23
25
 
24
 
from ... import (
25
 
    cache_utf8,
 
26
from brzlib import (
26
27
    osutils,
27
28
    timestamp,
28
29
    )
29
 
from . import apply_bundle
30
 
from ...errors import (
 
30
from brzlib.bundle import apply_bundle
 
31
from brzlib.errors import (
31
32
    TestamentMismatch,
32
33
    BzrError,
33
 
    NoSuchId,
34
34
    )
35
 
from ..inventory import (
 
35
from brzlib.inventory import (
36
36
    Inventory,
37
37
    InventoryDirectory,
38
38
    InventoryFile,
39
39
    InventoryLink,
40
40
    )
41
 
from ...osutils import sha_string, sha_strings, pathjoin
42
 
from ...revision import Revision, NULL_REVISION
43
 
from ..testament import StrictTestament
44
 
from ...trace import mutter, warning
45
 
from ...tree import (
46
 
    InterTree,
47
 
    Tree,
48
 
    )
49
 
from ..xml5 import serializer_v5
 
41
from brzlib.osutils import sha_string, pathjoin
 
42
from brzlib.revision import Revision, NULL_REVISION
 
43
from brzlib.testament import StrictTestament
 
44
from brzlib.trace import mutter, warning
 
45
from brzlib.tree import Tree
 
46
from brzlib.xml5 import serializer_v5
50
47
 
51
48
 
52
49
class RevisionInfo(object):
53
50
    """Gets filled out for each revision object that is read.
54
51
    """
55
 
 
56
52
    def __init__(self, revision_id):
57
53
        self.revision_id = revision_id
58
54
        self.sha1 = None
73
69
 
74
70
    def as_revision(self):
75
71
        rev = Revision(revision_id=self.revision_id,
76
 
                       committer=self.committer,
77
 
                       timestamp=float(self.timestamp),
78
 
                       timezone=int(self.timezone),
79
 
                       inventory_sha1=self.inventory_sha1,
80
 
                       message='\n'.join(self.message))
 
72
            committer=self.committer,
 
73
            timestamp=float(self.timestamp),
 
74
            timezone=int(self.timezone),
 
75
            inventory_sha1=self.inventory_sha1,
 
76
            message='\n'.join(self.message))
81
77
 
82
78
        if self.parent_ids:
83
79
            rev.parent_ids.extend(self.parent_ids)
92
88
                    value = ''
93
89
                else:
94
90
                    key = str(property[:key_end])
95
 
                    value = property[key_end + 2:]
 
91
                    value = property[key_end+2:]
96
92
                rev.properties[key] = value
97
93
 
98
94
        return rev
107
103
        revision_info.timestamp = revision.timestamp
108
104
        revision_info.message = revision.message.split('\n')
109
105
        revision_info.properties = [': '.join(p) for p in
110
 
                                    revision.properties.items()]
 
106
                                    revision.properties.iteritems()]
111
107
        return revision_info
112
108
 
113
109
 
115
111
    """This contains the meta information. Stuff that allows you to
116
112
    recreate the revision or inventory XML.
117
113
    """
118
 
 
119
114
    def __init__(self, bundle_format=None):
120
115
        self.bundle_format = None
121
116
        self.committer = None
145
140
        split up, based on the assumptions that can be made
146
141
        when information is missing.
147
142
        """
148
 
        from breezy.timestamp import unpack_highres_date
 
143
        from brzlib.timestamp import unpack_highres_date
149
144
        # Put in all of the guessable information.
150
145
        if not self.timestamp and self.date:
151
146
            self.timestamp, self.timezone = unpack_highres_date(self.date)
155
150
            if rev.timestamp is None:
156
151
                if rev.date is not None:
157
152
                    rev.timestamp, rev.timezone = \
158
 
                        unpack_highres_date(rev.date)
 
153
                            unpack_highres_date(rev.date)
159
154
                else:
160
155
                    rev.timestamp = self.timestamp
161
156
                    rev.timezone = self.timezone
210
205
        revision_info = self.get_revision_info(revision_id)
211
206
        inventory_revision_id = revision_id
212
207
        bundle_tree = BundleTree(repository.revision_tree(base),
213
 
                                 inventory_revision_id)
 
208
                                  inventory_revision_id)
214
209
        self._update_tree(bundle_tree, revision_id)
215
210
 
216
211
        inv = bundle_tree.inventory
226
221
        """
227
222
        rev_to_sha = {}
228
223
        inv_to_sha = {}
229
 
 
230
224
        def add_sha(d, revision_id, sha1):
231
225
            if revision_id is None:
232
226
                if sha1 is not None:
233
227
                    raise BzrError('A Null revision should always'
234
 
                                   'have a null sha1 hash')
 
228
                        'have a null sha1 hash')
235
229
                return
236
230
            if revision_id in d:
237
231
                # This really should have been validated as part
238
232
                # of _validate_revisions but lets do it again
239
233
                if sha1 != d[revision_id]:
240
234
                    raise BzrError('** Revision %r referenced with 2 different'
241
 
                                   ' sha hashes %s != %s' % (revision_id,
242
 
                                                             sha1, d[revision_id]))
 
235
                            ' sha hashes %s != %s' % (revision_id,
 
236
                                sha1, d[revision_id]))
243
237
            else:
244
238
                d[revision_id] = sha1
245
239
 
255
249
 
256
250
        count = 0
257
251
        missing = {}
258
 
        for revision_id, sha1 in rev_to_sha.items():
 
252
        for revision_id, sha1 in rev_to_sha.iteritems():
259
253
            if repository.has_revision(revision_id):
260
254
                testament = StrictTestament.from_revision(repository,
261
255
                                                          revision_id)
263
257
                                                                revision_id)
264
258
                if sha1 != local_sha1:
265
259
                    raise BzrError('sha1 mismatch. For revision id {%s}'
266
 
                                   'local: %s, bundle: %s' % (revision_id, local_sha1, sha1))
 
260
                            'local: %s, bundle: %s' % (revision_id, local_sha1, sha1))
267
261
                else:
268
262
                    count += 1
269
263
            elif revision_id not in checked:
281
275
        so build up an inventory, and make sure the hashes match.
282
276
        """
283
277
        # Now we should have a complete inventory entry.
284
 
        cs = serializer_v5.write_inventory_to_chunks(inv)
285
 
        sha1 = sha_strings(cs)
 
278
        s = serializer_v5.write_inventory_to_string(inv)
 
279
        sha1 = sha_string(s)
286
280
        # Target revision is the last entry in the real_revisions list
287
281
        rev = self.get_revision(revision_id)
288
282
        if rev.revision_id != revision_id:
289
283
            raise AssertionError()
290
284
        if sha1 != rev.inventory_sha1:
291
 
            with open(',,bogus-inv', 'wb') as f:
292
 
                f.writelines(cs)
 
285
            f = open(',,bogus-inv', 'wb')
 
286
            try:
 
287
                f.write(s)
 
288
            finally:
 
289
                f.close()
293
290
            warning('Inventory sha hash mismatch for revision %s. %s'
294
291
                    ' != %s' % (revision_id, sha1, rev.inventory_sha1))
295
292
 
296
 
    def _testament(self, revision, tree):
297
 
        raise NotImplementedError(self._testament)
298
 
 
299
293
    def _validate_revision(self, tree, revision_id):
300
294
        """Make sure all revision entries match their checksum."""
301
295
 
308
302
            raise AssertionError()
309
303
        if not (rev.revision_id == revision_id):
310
304
            raise AssertionError()
311
 
        testament = self._testament(rev, tree)
312
 
        sha1 = testament.as_sha1()
 
305
        sha1 = self._testament_sha1(rev, tree)
313
306
        if sha1 != rev_info.sha1:
314
307
            raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
315
308
        if rev.revision_id in rev_to_sha1:
316
309
            raise BzrError('Revision {%s} given twice in the list'
317
 
                           % (rev.revision_id))
 
310
                    % (rev.revision_id))
318
311
        rev_to_sha1[rev.revision_id] = sha1
319
312
 
320
313
    def _update_tree(self, bundle_tree, revision_id):
328
321
            if last_changed is not None:
329
322
                # last_changed will be a Unicode string because of how it was
330
323
                # read. Convert it back to utf8.
331
 
                changed_revision_id = cache_utf8.encode(last_changed)
 
324
                changed_revision_id = osutils.safe_revision_id(last_changed,
 
325
                                                               warn=False)
332
326
            else:
333
327
                changed_revision_id = revision_id
334
328
            bundle_tree.note_last_changed(path, changed_revision_id)
355
349
 
356
350
        def do_patch(path, lines, encoding):
357
351
            if encoding == 'base64':
358
 
                patch = base64.b64decode(b''.join(lines))
 
352
                patch = base64.decodestring(''.join(lines))
359
353
            elif encoding is None:
360
 
                patch = b''.join(lines)
 
354
                patch =  ''.join(lines)
361
355
            else:
362
356
                raise ValueError(encoding)
363
357
            bundle_tree.note_patch(path, patch)
366
360
            info = extra.split(' // ')
367
361
            if len(info) < 2:
368
362
                raise BzrError('renamed action lines need both a from and to'
369
 
                               ': %r' % extra)
 
363
                        ': %r' % extra)
370
364
            old_path = info[0]
371
365
            if info[1].startswith('=> '):
372
366
                new_path = info[1][3:]
385
379
                # TODO: in the future we might allow file ids to be
386
380
                # given for removed entries
387
381
                raise BzrError('removed action lines should only have the path'
388
 
                               ': %r' % extra)
 
382
                        ': %r' % extra)
389
383
            path = info[0]
390
384
            bundle_tree.note_deletion(path)
391
385
 
393
387
            info = extra.split(' // ')
394
388
            if len(info) <= 1:
395
389
                raise BzrError('add action lines require the path and file id'
396
 
                               ': %r' % extra)
 
390
                        ': %r' % extra)
397
391
            elif len(info) > 5:
398
392
                raise BzrError('add action lines have fewer than 5 entries.'
399
 
                               ': %r' % extra)
 
393
                        ': %r' % extra)
400
394
            path = info[0]
401
395
            if not info[1].startswith('file-id:'):
402
396
                raise BzrError('The file-id should follow the path for an add'
403
 
                               ': %r' % extra)
 
397
                        ': %r' % extra)
404
398
            # This will be Unicode because of how the stream is read. Turn it
405
399
            # back into a utf8 file_id
406
 
            file_id = cache_utf8.encode(info[1][8:])
 
400
            file_id = osutils.safe_file_id(info[1][8:], warn=False)
407
401
 
408
402
            bundle_tree.note_id(file_id, path, kind)
409
403
            # this will be overridden in extra_info if executable is specified.
418
412
            info = extra.split(' // ')
419
413
            if len(info) < 1:
420
414
                raise BzrError('modified action lines have at least'
421
 
                               'the path in them: %r' % extra)
 
415
                        'the path in them: %r' % extra)
422
416
            path = info[0]
423
417
 
424
418
            last_modified, encoding = extra_info(info[1:], path)
427
421
                do_patch(path, lines, encoding)
428
422
 
429
423
        valid_actions = {
430
 
            'renamed': renamed,
431
 
            'removed': removed,
432
 
            'added': added,
433
 
            'modified': modified
 
424
            'renamed':renamed,
 
425
            'removed':removed,
 
426
            'added':added,
 
427
            'modified':modified
434
428
        }
435
429
        for action_line, lines in \
436
 
                self.get_revision_info(revision_id).tree_actions:
 
430
            self.get_revision_info(revision_id).tree_actions:
437
431
            first = action_line.find(' ')
438
432
            if first == -1:
439
433
                raise BzrError('Bogus action line'
440
 
                               ' (no opening space): %r' % action_line)
441
 
            second = action_line.find(' ', first + 1)
 
434
                        ' (no opening space): %r' % action_line)
 
435
            second = action_line.find(' ', first+1)
442
436
            if second == -1:
443
437
                raise BzrError('Bogus action line'
444
 
                               ' (missing second space): %r' % action_line)
 
438
                        ' (missing second space): %r' % action_line)
445
439
            action = action_line[:first]
446
 
            kind = action_line[first + 1:second]
 
440
            kind = action_line[first+1:second]
447
441
            if kind not in ('file', 'directory', 'symlink'):
448
442
                raise BzrError('Bogus action line'
449
 
                               ' (invalid object kind %r): %r' % (kind, action_line))
450
 
            extra = action_line[second + 1:]
 
443
                        ' (invalid object kind %r): %r' % (kind, action_line))
 
444
            extra = action_line[second+1:]
451
445
 
452
446
            if action not in valid_actions:
453
447
                raise BzrError('Bogus action line'
454
 
                               ' (unrecognized action): %r' % action_line)
 
448
                        ' (unrecognized action): %r' % action_line)
455
449
            valid_actions[action](kind, extra, lines)
456
450
 
457
451
    def install_revisions(self, target_repo, stream_input=True):
475
469
 
476
470
    def __init__(self, base_tree, revision_id):
477
471
        self.base_tree = base_tree
478
 
        self._renamed = {}  # Mapping from old_path => new_path
479
 
        self._renamed_r = {}  # new_path => old_path
480
 
        self._new_id = {}  # new_path => new_id
481
 
        self._new_id_r = {}  # new_id => new_path
482
 
        self._kinds = {}  # new_path => kind
483
 
        self._last_changed = {}  # new_id => revision_id
484
 
        self._executable = {}  # new_id => executable value
 
472
        self._renamed = {} # Mapping from old_path => new_path
 
473
        self._renamed_r = {} # new_path => old_path
 
474
        self._new_id = {} # new_path => new_id
 
475
        self._new_id_r = {} # new_id => new_path
 
476
        self._kinds = {} # new_id => kind
 
477
        self._last_changed = {} # new_id => revision_id
 
478
        self._executable = {} # new_id => executable value
485
479
        self.patches = {}
486
 
        self._targets = {}  # new path => new symlink target
 
480
        self._targets = {} # new path => new symlink target
487
481
        self.deleted = []
 
482
        self.contents_by_id = True
488
483
        self.revision_id = revision_id
489
484
        self._inventory = None
490
 
        self._base_inter = InterTree.get(self.base_tree, self)
491
485
 
492
486
    def __str__(self):
493
487
        return pprint.pformat(self.__dict__)
505
499
        """Files that don't exist in base need a new id."""
506
500
        self._new_id[new_path] = new_id
507
501
        self._new_id_r[new_id] = new_path
508
 
        self._kinds[new_path] = kind
 
502
        self._kinds[new_id] = kind
509
503
 
510
504
    def note_last_changed(self, file_id, revision_id):
511
505
        if (file_id in self._last_changed
512
506
                and self._last_changed[file_id] != revision_id):
513
507
            raise BzrError('Mismatched last-changed revision for file_id {%s}'
514
 
                           ': %s != %s' % (file_id,
515
 
                                           self._last_changed[file_id],
516
 
                                           revision_id))
 
508
                    ': %s != %s' % (file_id,
 
509
                                    self._last_changed[file_id],
 
510
                                    revision_id))
517
511
        self._last_changed[file_id] = revision_id
518
512
 
519
513
    def note_patch(self, new_path, patch):
538
532
        old_path = self._renamed.get(new_path)
539
533
        if old_path is not None:
540
534
            return old_path
541
 
        dirname, basename = os.path.split(new_path)
 
535
        dirname,basename = os.path.split(new_path)
542
536
        # dirname is not '' doesn't work, because
543
537
        # dirname may be a unicode entry, and is
544
538
        # requires the objects to be identical
550
544
                old_path = pathjoin(old_dir, basename)
551
545
        else:
552
546
            old_path = new_path
553
 
        # If the new path wasn't in renamed, the old one shouldn't be in
554
 
        # renamed_r
 
547
        #If the new path wasn't in renamed, the old one shouldn't be in
 
548
        #renamed_r
555
549
        if old_path in self._renamed_r:
556
550
            return None
557
551
        return old_path
567
561
            return new_path
568
562
        if new_path in self._renamed:
569
563
            return None
570
 
        dirname, basename = os.path.split(old_path)
 
564
        dirname,basename = os.path.split(old_path)
571
565
        if dirname != '':
572
566
            new_dir = self.new_path(dirname)
573
567
            if new_dir is None:
576
570
                new_path = pathjoin(new_dir, basename)
577
571
        else:
578
572
            new_path = old_path
579
 
        # If the old path wasn't in renamed, the new one shouldn't be in
580
 
        # renamed_r
 
573
        #If the old path wasn't in renamed, the new one shouldn't be in
 
574
        #renamed_r
581
575
        if new_path in self._renamed:
582
576
            return None
583
577
        return new_path
584
578
 
 
579
    def get_root_id(self):
 
580
        return self.path2id('')
 
581
 
585
582
    def path2id(self, path):
586
583
        """Return the id of the file present at path in the target tree."""
587
584
        file_id = self._new_id.get(path)
594
591
            return None
595
592
        return self.base_tree.path2id(old_path)
596
593
 
597
 
    def id2path(self, file_id, recurse='down'):
 
594
    def id2path(self, file_id):
598
595
        """Return the new path in the target tree of the file with id file_id"""
599
596
        path = self._new_id_r.get(file_id)
600
597
        if path is not None:
601
598
            return path
602
 
        old_path = self.base_tree.id2path(file_id, recurse)
 
599
        old_path = self.base_tree.id2path(file_id)
603
600
        if old_path is None:
604
 
            raise NoSuchId(file_id, self)
 
601
            return None
605
602
        if old_path in self.deleted:
606
 
            raise NoSuchId(file_id, self)
607
 
        new_path = self.new_path(old_path)
608
 
        if new_path is None:
609
 
            raise NoSuchId(file_id, self)
610
 
        return new_path
611
 
 
612
 
    def get_file(self, path):
 
603
            return None
 
604
        return self.new_path(old_path)
 
605
 
 
606
    def old_contents_id(self, file_id):
 
607
        """Return the id in the base_tree for the given file_id.
 
608
        Return None if the file did not exist in base.
 
609
        """
 
610
        if self.contents_by_id:
 
611
            if self.base_tree.has_id(file_id):
 
612
                return file_id
 
613
            else:
 
614
                return None
 
615
        new_path = self.id2path(file_id)
 
616
        return self.base_tree.path2id(new_path)
 
617
 
 
618
    def get_file(self, file_id):
613
619
        """Return a file-like object containing the new contents of the
614
620
        file given by file_id.
615
621
 
617
623
                in the text-store, so that the file contents would
618
624
                then be cached.
619
625
        """
620
 
        old_path = self._base_inter.find_source_path(path)
621
 
        if old_path is None:
 
626
        base_id = self.old_contents_id(file_id)
 
627
        if (base_id is not None and
 
628
            base_id != self.base_tree.get_root_id()):
 
629
            patch_original = self.base_tree.get_file(base_id)
 
630
        else:
622
631
            patch_original = None
623
 
        else:
624
 
            patch_original = self.base_tree.get_file(old_path)
625
 
        file_patch = self.patches.get(path)
 
632
        file_patch = self.patches.get(self.id2path(file_id))
626
633
        if file_patch is None:
627
634
            if (patch_original is None and
628
 
                    self.kind(path) == 'directory'):
629
 
                return BytesIO()
 
635
                self.kind(file_id) == 'directory'):
 
636
                return StringIO()
630
637
            if patch_original is None:
631
638
                raise AssertionError("None: %s" % file_id)
632
639
            return patch_original
633
640
 
634
 
        if file_patch.startswith(b'\\'):
 
641
        if file_patch.startswith('\\'):
635
642
            raise ValueError(
636
643
                'Malformed patch for %s, %r' % (file_id, file_patch))
637
644
        return patched_file(file_patch, patch_original)
638
645
 
639
 
    def get_symlink_target(self, path):
 
646
    def get_symlink_target(self, file_id, path=None):
 
647
        if path is None:
 
648
            path = self.id2path(file_id)
640
649
        try:
641
650
            return self._targets[path]
642
651
        except KeyError:
643
 
            old_path = self.old_path(path)
644
 
            return self.base_tree.get_symlink_target(old_path)
645
 
 
646
 
    def kind(self, path):
647
 
        try:
648
 
            return self._kinds[path]
649
 
        except KeyError:
650
 
            old_path = self.old_path(path)
651
 
            return self.base_tree.kind(old_path)
652
 
 
653
 
    def get_file_revision(self, path):
 
652
            return self.base_tree.get_symlink_target(file_id)
 
653
 
 
654
    def kind(self, file_id):
 
655
        if file_id in self._kinds:
 
656
            return self._kinds[file_id]
 
657
        return self.base_tree.kind(file_id)
 
658
 
 
659
    def get_file_revision(self, file_id):
 
660
        path = self.id2path(file_id)
654
661
        if path in self._last_changed:
655
662
            return self._last_changed[path]
656
663
        else:
657
 
            old_path = self.old_path(path)
658
 
            return self.base_tree.get_file_revision(old_path)
 
664
            return self.base_tree.get_file_revision(file_id)
659
665
 
660
 
    def is_executable(self, path):
 
666
    def is_executable(self, file_id):
 
667
        path = self.id2path(file_id)
661
668
        if path in self._executable:
662
669
            return self._executable[path]
663
670
        else:
664
 
            old_path = self.old_path(path)
665
 
            return self.base_tree.is_executable(old_path)
 
671
            return self.base_tree.is_executable(file_id)
666
672
 
667
 
    def get_last_changed(self, path):
 
673
    def get_last_changed(self, file_id):
 
674
        path = self.id2path(file_id)
668
675
        if path in self._last_changed:
669
676
            return self._last_changed[path]
670
 
        old_path = self.old_path(path)
671
 
        return self.base_tree.get_file_revision(old_path)
 
677
        return self.base_tree.get_file_revision(file_id)
672
678
 
673
 
    def get_size_and_sha1(self, new_path):
 
679
    def get_size_and_sha1(self, file_id):
674
680
        """Return the size and sha1 hash of the given file id.
675
681
        If the file was not locally modified, this is extracted
676
682
        from the base_tree. Rather than re-reading the file.
677
683
        """
 
684
        new_path = self.id2path(file_id)
678
685
        if new_path is None:
679
686
            return None, None
680
687
        if new_path not in self.patches:
681
688
            # If the entry does not have a patch, then the
682
689
            # contents must be the same as in the base_tree
683
 
            base_path = self.old_path(new_path)
684
 
            text_size = self.base_tree.get_file_size(base_path)
685
 
            text_sha1 = self.base_tree.get_file_sha1(base_path)
 
690
            text_size = self.base_tree.get_file_size(file_id)
 
691
            text_sha1 = self.base_tree.get_file_sha1(file_id)
686
692
            return text_size, text_sha1
687
 
        fileobj = self.get_file(new_path)
 
693
        fileobj = self.get_file(file_id)
688
694
        content = fileobj.read()
689
695
        return len(content), sha_string(content)
690
696
 
696
702
        from os.path import dirname, basename
697
703
        inv = Inventory(None, self.revision_id)
698
704
 
699
 
        def add_entry(path, file_id):
 
705
        def add_entry(file_id):
 
706
            path = self.id2path(file_id)
 
707
            if path is None:
 
708
                return
700
709
            if path == '':
701
710
                parent_id = None
702
711
            else:
703
712
                parent_path = dirname(path)
704
713
                parent_id = self.path2id(parent_path)
705
714
 
706
 
            kind = self.kind(path)
707
 
            revision_id = self.get_last_changed(path)
 
715
            kind = self.kind(file_id)
 
716
            revision_id = self.get_last_changed(file_id)
708
717
 
709
718
            name = basename(path)
710
719
            if kind == 'directory':
711
720
                ie = InventoryDirectory(file_id, name, parent_id)
712
721
            elif kind == 'file':
713
722
                ie = InventoryFile(file_id, name, parent_id)
714
 
                ie.executable = self.is_executable(path)
 
723
                ie.executable = self.is_executable(file_id)
715
724
            elif kind == 'symlink':
716
725
                ie = InventoryLink(file_id, name, parent_id)
717
 
                ie.symlink_target = self.get_symlink_target(path)
 
726
                ie.symlink_target = self.get_symlink_target(file_id, path)
718
727
            ie.revision = revision_id
719
728
 
720
729
            if kind == 'file':
721
 
                ie.text_size, ie.text_sha1 = self.get_size_and_sha1(path)
 
730
                ie.text_size, ie.text_sha1 = self.get_size_and_sha1(file_id)
722
731
                if ie.text_size is None:
723
732
                    raise BzrError(
724
733
                        'Got a text_size of None for file_id %r' % file_id)
726
735
 
727
736
        sorted_entries = self.sorted_path_id()
728
737
        for path, file_id in sorted_entries:
729
 
            add_entry(path, file_id)
 
738
            add_entry(file_id)
730
739
 
731
740
        return inv
732
741
 
740
749
    root_inventory = property(_get_inventory)
741
750
 
742
751
    def all_file_ids(self):
743
 
        return {entry.file_id for path, entry in self.inventory.iter_entries()}
744
 
 
745
 
    def all_versioned_paths(self):
746
 
        return {path for path, entry in self.inventory.iter_entries()}
 
752
        return set(
 
753
            [entry.file_id for path, entry in self.inventory.iter_entries()])
747
754
 
748
755
    def list_files(self, include_root=False, from_dir=None, recursive=True):
749
756
        # The only files returned by this are those from the version
757
764
                return
758
765
        entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
759
766
        if inv.root is not None and not include_root and from_dir is None:
760
 
            # skip the root for compatibility with the current apis.
761
 
            next(entries)
 
767
            # skip the root for compatability with the current apis.
 
768
            entries.next()
762
769
        for path, entry in entries:
763
 
            yield path, 'V', entry.kind, entry
 
770
            yield path, 'V', entry.kind, entry.file_id, entry
764
771
 
765
772
    def sorted_path_id(self):
766
773
        paths = []
767
 
        for result in self._new_id.items():
 
774
        for result in self._new_id.iteritems():
768
775
            paths.append(result)
769
776
        for id in self.base_tree.all_file_ids():
770
 
            try:
771
 
                path = self.id2path(id, recurse='none')
772
 
            except NoSuchId:
 
777
            path = self.id2path(id)
 
778
            if path is None:
773
779
                continue
774
780
            paths.append((path, id))
775
781
        paths.sort()
778
784
 
779
785
def patched_file(file_patch, original):
780
786
    """Produce a file-like object with the patched version of a text"""
781
 
    from breezy.patches import iter_patched
782
 
    from breezy.iterablefile import IterableFile
783
 
    if file_patch == b"":
 
787
    from brzlib.patches import iter_patched
 
788
    from brzlib.iterablefile import IterableFile
 
789
    if file_patch == "":
784
790
        return IterableFile(())
785
791
    # string.splitlines(True) also splits on '\r', but the iter_patched code
786
792
    # only expects to iterate over '\n' style lines
787
793
    return IterableFile(iter_patched(original,
788
 
                                     BytesIO(file_patch).readlines()))
 
794
                StringIO(file_patch).readlines()))