~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: John Arbash Meinel
  • Date: 2006-10-11 00:23:23 UTC
  • mfrom: (2070 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2071.
  • Revision ID: john@arbash-meinel.com-20061011002323-82ba88c293d7caff
[merge] bzr.dev 2070

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
"""
19
19
 
20
20
import os
21
 
from collections import deque
22
21
from cStringIO import StringIO
 
22
from warnings import warn
23
23
 
24
24
import bzrlib
25
 
from bzrlib import (
26
 
    delta,
27
 
    osutils,
28
 
    symbol_versioning,
29
 
    )
 
25
from bzrlib import delta
30
26
from bzrlib.decorators import needs_read_lock
31
27
from bzrlib.errors import BzrError, BzrCheckError
32
28
from bzrlib import errors
33
 
from bzrlib.inventory import Inventory, InventoryFile
 
29
from bzrlib.inventory import Inventory
34
30
from bzrlib.inter import InterObject
35
31
from bzrlib.osutils import fingerprint_file
36
32
import bzrlib.revision
58
54
    """
59
55
    
60
56
    def changes_from(self, other, want_unchanged=False, specific_files=None,
61
 
        extra_trees=None, require_versioned=False, include_root=False,
62
 
        want_unversioned=False):
 
57
        extra_trees=None, require_versioned=False, include_root=False):
63
58
        """Return a TreeDelta of the changes from other to this tree.
64
59
 
65
60
        :param other: A tree to compare with.
74
69
        :param require_versioned: An optional boolean (defaults to False). When
75
70
            supplied and True all the 'specific_files' must be versioned, or
76
71
            a PathsNotVersionedError will be thrown.
77
 
        :param want_unversioned: Scan for unversioned paths.
78
72
 
79
73
        The comparison will be performed by an InterTree object looked up on 
80
74
        self and other.
87
81
            specific_files=specific_files,
88
82
            extra_trees=extra_trees,
89
83
            require_versioned=require_versioned,
90
 
            include_root=include_root,
91
 
            want_unversioned=want_unversioned,
 
84
            include_root=include_root
92
85
            )
93
 
 
94
 
    def _iter_changes(self, from_tree, include_unchanged=False,
95
 
                     specific_files=None, pb=None, extra_trees=None,
96
 
                     require_versioned=True, want_unversioned=False):
97
 
        intertree = InterTree.get(from_tree, self)
98
 
        return intertree._iter_changes(include_unchanged, specific_files, pb,
99
 
            extra_trees, require_versioned, want_unversioned=want_unversioned)
100
86
    
101
87
    def conflicts(self):
102
88
        """Get a list of the conflicts in the tree.
105
91
        """
106
92
        return []
107
93
 
108
 
    def extras(self):
109
 
        """For trees that can have unversioned files, return all such paths."""
110
 
        return []
111
 
 
112
94
    def get_parent_ids(self):
113
95
        """Get the parent ids for this tree. 
114
96
 
123
105
        raise NotImplementedError()
124
106
 
125
107
    def has_id(self, file_id):
126
 
        file_id = osutils.safe_file_id(file_id)
127
108
        return self.inventory.has_id(file_id)
128
109
 
129
110
    __contains__ = has_id
130
111
 
131
112
    def has_or_had_id(self, file_id):
132
 
        file_id = osutils.safe_file_id(file_id)
133
113
        if file_id == self.inventory.root.file_id:
134
114
            return True
135
115
        return self.inventory.has_id(file_id)
136
116
 
137
 
    def is_ignored(self, filename):
138
 
        """Check whether the filename is ignored by this tree.
139
 
 
140
 
        :param filename: The relative filename within the tree.
141
 
        :return: True if the filename is ignored.
142
 
        """
143
 
        return False
144
 
 
145
117
    def __iter__(self):
146
118
        return iter(self.inventory)
147
119
 
148
120
    def id2path(self, file_id):
149
 
        """Return the path for a file id.
150
 
 
151
 
        :raises NoSuchId:
152
 
        """
153
 
        file_id = osutils.safe_file_id(file_id)
154
121
        return self.inventory.id2path(file_id)
155
122
 
156
123
    def is_control_filename(self, filename):
165
132
        """
166
133
        return self.bzrdir.is_control_filename(filename)
167
134
 
168
 
    @needs_read_lock
169
 
    def iter_entries_by_dir(self, specific_file_ids=None):
 
135
    def iter_entries_by_dir(self):
170
136
        """Walk the tree in 'by_dir' order.
171
137
 
172
138
        This will yield each entry in the tree as a (path, entry) tuple. The
174
140
        preceeded by the parent of a directory, and all the contents of a 
175
141
        directory are grouped together.
176
142
        """
177
 
        return self.inventory.iter_entries_by_dir(
178
 
            specific_file_ids=specific_file_ids)
179
 
 
180
 
    def iter_references(self):
181
 
        for path, entry in self.iter_entries_by_dir():
182
 
            if entry.kind == 'tree-reference':
183
 
                yield path, entry.file_id
 
143
        return self.inventory.iter_entries_by_dir()
184
144
 
185
145
    def kind(self, file_id):
186
 
        raise NotImplementedError("Tree subclass %s must implement kind"
187
 
            % self.__class__.__name__)
188
 
 
189
 
    def get_reference_revision(self, file_id, path=None):
190
 
        raise NotImplementedError("Tree subclass %s must implement "
191
 
                                  "get_reference_revision"
192
 
            % self.__class__.__name__)
193
 
 
194
 
    def _comparison_data(self, entry, path):
195
 
        """Return a tuple of kind, executable, stat_value for a file.
196
 
 
197
 
        entry may be None if there is no inventory entry for the file, but
198
 
        path must always be supplied.
199
 
 
200
 
        kind is None if there is no file present (even if an inventory id is
201
 
        present).  executable is False for non-file entries.
202
 
        """
203
 
        raise NotImplementedError(self._comparison_data)
204
 
 
205
 
    def _file_size(self, entry, stat_value):
206
 
        raise NotImplementedError(self._file_size)
 
146
        raise NotImplementedError("subclasses must implement kind")
207
147
 
208
148
    def _get_inventory(self):
209
149
        return self._inventory
211
151
    def get_file(self, file_id):
212
152
        """Return a file object for the file file_id in the tree."""
213
153
        raise NotImplementedError(self.get_file)
214
 
 
215
 
    def get_file_mtime(self, file_id, path=None):
216
 
        """Return the modification time for a file.
217
 
 
218
 
        :param file_id: The handle for this file.
219
 
        :param path: The path that this file can be found at.
220
 
            These must point to the same object.
221
 
        """
222
 
        raise NotImplementedError(self.get_file_mtime)
223
 
 
 
154
    
224
155
    def get_file_by_path(self, path):
225
156
        return self.get_file(self._inventory.path2id(path))
226
157
 
227
 
    def get_symlink_target(self, file_id):
228
 
        """Get the target for a given file_id.
229
 
 
230
 
        It is assumed that the caller already knows that file_id is referencing
231
 
        a symlink.
232
 
        :param file_id: Handle for the symlink entry.
233
 
        :return: The path the symlink points to.
234
 
        """
235
 
        raise NotImplementedError(self.get_symlink_target)
236
 
 
237
 
    def annotate_iter(self, file_id):
238
 
        """Return an iterator of revision_id, line tuples
239
 
 
240
 
        For working trees (and mutable trees in general), the special
241
 
        revision_id 'current:' will be used for lines that are new in this
242
 
        tree, e.g. uncommitted changes.
243
 
        :param file_id: The file to produce an annotated version from
244
 
        """
245
 
        raise NotImplementedError(self.annotate_iter)
246
 
 
247
158
    inventory = property(_get_inventory,
248
159
                         doc="Inventory of this Tree")
249
160
 
270
181
        """Return the id for path in this tree."""
271
182
        return self._inventory.path2id(path)
272
183
 
273
 
    def paths2ids(self, paths, trees=[], require_versioned=True):
274
 
        """Return all the ids that can be reached by walking from paths.
275
 
        
276
 
        Each path is looked up in each this tree and any extras provided in
277
 
        trees, and this is repeated recursively: the children in an extra tree
278
 
        of a directory that has been renamed under a provided path in this tree
279
 
        are all returned, even if none exist until a provided path in this
280
 
        tree, and vice versa.
281
 
 
282
 
        :param paths: An iterable of paths to start converting to ids from.
283
 
            Alternatively, if paths is None, no ids should be calculated and None
284
 
            will be returned. This is offered to make calling the api unconditional
285
 
            for code that *might* take a list of files.
286
 
        :param trees: Additional trees to consider.
287
 
        :param require_versioned: If False, do not raise NotVersionedError if
288
 
            an element of paths is not versioned in this tree and all of trees.
289
 
        """
290
 
        return find_ids_across_trees(paths, [self] + list(trees), require_versioned)
291
 
 
292
184
    def print_file(self, file_id):
293
185
        """Print file with id `file_id` to stdout."""
294
 
        file_id = osutils.safe_file_id(file_id)
295
186
        import sys
296
187
        sys.stdout.write(self.get_file_text(file_id))
297
188
 
298
189
    def lock_read(self):
299
190
        pass
300
191
 
301
 
    def revision_tree(self, revision_id):
302
 
        """Obtain a revision tree for the revision revision_id.
303
 
 
304
 
        The intention of this method is to allow access to possibly cached
305
 
        tree data. Implementors of this method should raise NoSuchRevision if
306
 
        the tree is not locally available, even if they could obtain the 
307
 
        tree via a repository or some other means. Callers are responsible 
308
 
        for finding the ultimate source for a revision tree.
309
 
 
310
 
        :param revision_id: The revision_id of the requested tree.
311
 
        :return: A Tree.
312
 
        :raises: NoSuchRevision if the tree cannot be obtained.
313
 
        """
314
 
        raise errors.NoSuchRevisionInTree(self, revision_id)
315
 
 
316
192
    def unknowns(self):
317
193
        """What files are present in this tree and unknown.
318
194
        
324
200
        pass
325
201
 
326
202
    def filter_unversioned_files(self, paths):
327
 
        """Filter out paths that are versioned.
 
203
        """Filter out paths that are not versioned.
328
204
 
329
205
        :return: set of paths.
330
206
        """
334
210
        pred = self.inventory.has_filename
335
211
        return set((p for p in paths if not pred(p)))
336
212
 
337
 
    def walkdirs(self, prefix=""):
338
 
        """Walk the contents of this tree from path down.
339
 
 
340
 
        This yields all the data about the contents of a directory at a time.
341
 
        After each directory has been yielded, if the caller has mutated the
342
 
        list to exclude some directories, they are then not descended into.
343
 
        
344
 
        The data yielded is of the form:
345
 
        ((directory-relpath, directory-path-from-root, directory-fileid),
346
 
        [(relpath, basename, kind, lstat, path_from_tree_root, file_id, 
347
 
          versioned_kind), ...]),
348
 
         - directory-relpath is the containing dirs relpath from prefix
349
 
         - directory-path-from-root is the containing dirs path from /
350
 
         - directory-fileid is the id of the directory if it is versioned.
351
 
         - relpath is the relative path within the subtree being walked.
352
 
         - basename is the basename
353
 
         - kind is the kind of the file now. If unknonwn then the file is not
354
 
           present within the tree - but it may be recorded as versioned. See
355
 
           versioned_kind.
356
 
         - lstat is the stat data *if* the file was statted.
357
 
         - path_from_tree_root is the path from the root of the tree.
358
 
         - file_id is the file_id is the entry is versioned.
359
 
         - versioned_kind is the kind of the file as last recorded in the 
360
 
           versioning system. If 'unknown' the file is not versioned.
361
 
        One of 'kind' and 'versioned_kind' must not be 'unknown'.
362
 
 
363
 
        :param prefix: Start walking from prefix within the tree rather than
364
 
        at the root. This allows one to walk a subtree but get paths that are
365
 
        relative to a tree rooted higher up.
366
 
        :return: an iterator over the directory data.
367
 
        """
368
 
        raise NotImplementedError(self.walkdirs)
369
 
 
 
213
 
 
214
# for compatibility
 
215
from bzrlib.revisiontree import RevisionTree
 
216
 
370
217
 
371
218
class EmptyTree(Tree):
372
219
 
373
220
    def __init__(self):
374
 
        self._inventory = Inventory(root_id=None)
375
 
        symbol_versioning.warn('EmptyTree is deprecated as of bzr 0.9 please'
376
 
                               ' use repository.revision_tree instead.',
377
 
                               DeprecationWarning, stacklevel=2)
 
221
        self._inventory = Inventory()
 
222
        warn('EmptyTree is deprecated as of bzr 0.9 please use '
 
223
            'repository.revision_tree instead.',
 
224
            DeprecationWarning, stacklevel=2)
378
225
 
379
226
    def get_parent_ids(self):
380
227
        return []
386
233
        return False
387
234
 
388
235
    def kind(self, file_id):
389
 
        file_id = osutils.safe_file_id(file_id)
390
236
        assert self._inventory[file_id].kind == "directory"
391
237
        return "directory"
392
238
 
393
 
    def list_files(self, include_root=False):
 
239
    def list_files(self):
394
240
        return iter([])
395
241
    
396
242
    def __contains__(self, file_id):
397
 
        file_id = osutils.safe_file_id(file_id)
398
243
        return (file_id in self._inventory)
399
244
 
400
 
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
245
    def get_file_sha1(self, file_id, path=None):
401
246
        return None
402
247
 
403
248
 
472
317
    All matches in all trees will be used, and all children of matched
473
318
    directories will be used.
474
319
 
475
 
    :param filenames: The filenames to find file_ids for (if None, returns
476
 
        None)
 
320
    :param filenames: The filenames to find file_ids for
477
321
    :param trees: The trees to find file_ids within
478
322
    :param require_versioned: if true, all specified filenames must occur in
479
323
    at least one tree.
481
325
    """
482
326
    if not filenames:
483
327
        return None
484
 
    specified_path_ids = _find_ids_across_trees(filenames, trees,
485
 
        require_versioned)
486
 
    return _find_children_across_trees(specified_path_ids, trees)
487
 
 
488
 
 
489
 
def _find_ids_across_trees(filenames, trees, require_versioned):
 
328
    specified_ids = _find_filename_ids_across_trees(filenames, trees, 
 
329
                                                    require_versioned)
 
330
    return _find_children_across_trees(specified_ids, trees)
 
331
 
 
332
 
 
333
def _find_filename_ids_across_trees(filenames, trees, require_versioned):
490
334
    """Find the ids corresponding to specified filenames.
491
335
    
492
 
    All matches in all trees will be used, but subdirectories are not scanned.
 
336
    All matches in all trees will be used.
493
337
 
494
338
    :param filenames: The filenames to find file_ids for
495
339
    :param trees: The trees to find file_ids within
496
340
    :param require_versioned: if true, all specified filenames must occur in
497
 
        at least one tree.
498
 
    :return: a set of (path, file ids) for the specified filenames
 
341
    at least one tree.
 
342
    :return: a set of file ids for the specified filenames
499
343
    """
500
344
    not_versioned = []
501
345
    interesting_ids = set()
502
346
    for tree_path in filenames:
503
347
        not_found = True
504
348
        for tree in trees:
505
 
            file_id = tree.path2id(tree_path)
 
349
            file_id = tree.inventory.path2id(tree_path)
506
350
            if file_id is not None:
507
351
                interesting_ids.add(file_id)
508
352
                not_found = False
529
373
        new_pending = set()
530
374
        for file_id in pending:
531
375
            for tree in trees:
532
 
                if not tree.has_id(file_id):
 
376
                if file_id not in tree:
533
377
                    continue
534
378
                entry = tree.inventory[file_id]
535
379
                for child in getattr(entry, 'children', {}).itervalues():
555
399
 
556
400
    @needs_read_lock
557
401
    def compare(self, want_unchanged=False, specific_files=None,
558
 
        extra_trees=None, require_versioned=False, include_root=False,
559
 
        want_unversioned=False):
 
402
        extra_trees=None, require_versioned=False, include_root=False):
560
403
        """Return the changes from source to target.
561
404
 
562
405
        :return: A TreeDelta.
571
414
        :param require_versioned: An optional boolean (defaults to False). When
572
415
            supplied and True all the 'specific_files' must be versioned, or
573
416
            a PathsNotVersionedError will be thrown.
574
 
        :param want_unversioned: Scan for unversioned paths.
575
417
        """
576
 
        # NB: show_status depends on being able to pass in non-versioned files
577
 
        # and report them as unknown
578
 
        trees = (self.source,)
 
418
        # NB: show_status depends on being able to pass in non-versioned files and
 
419
        # report them as unknown
 
420
        trees = (self.source, self.target)
579
421
        if extra_trees is not None:
580
422
            trees = trees + tuple(extra_trees)
581
 
        # target is usually the newer tree:
582
 
        specific_file_ids = self.target.paths2ids(specific_files, trees,
583
 
            require_versioned=require_versioned)
 
423
        specific_file_ids = find_ids_across_trees(specific_files,
 
424
            trees, require_versioned=require_versioned)
584
425
        if specific_files and not specific_file_ids:
585
426
            # All files are unversioned, so just return an empty delta
586
427
            # _compare_trees would think we want a complete delta
587
 
            result = delta.TreeDelta()
588
 
            fake_entry = InventoryFile('unused', 'unused', 'unused')
589
 
            result.unversioned = [(path, None,
590
 
                self.target._comparison_data(fake_entry, path)[0]) for path in
591
 
                specific_files]
592
 
            return result
 
428
            return delta.TreeDelta()
593
429
        return delta._compare_trees(self.source, self.target, want_unchanged,
594
 
            specific_files, include_root, extra_trees=extra_trees,
595
 
            want_unversioned=want_unversioned)
596
 
 
597
 
    def _iter_changes(self, include_unchanged=False,
598
 
                      specific_files=None, pb=None, extra_trees=[],
599
 
                      require_versioned=True, want_unversioned=False):
600
 
        """Generate an iterator of changes between trees.
601
 
 
602
 
        A tuple is returned:
603
 
        (file_id, (path_in_source, path_in_target),
604
 
         changed_content, versioned, parent, name, kind,
605
 
         executable)
606
 
 
607
 
        Changed_content is True if the file's content has changed.  This
608
 
        includes changes to its kind, and to a symlink's target.
609
 
 
610
 
        versioned, parent, name, kind, executable are tuples of (from, to).
611
 
        If a file is missing in a tree, its kind is None.
612
 
 
613
 
        Iteration is done in parent-to-child order, relative to the target
614
 
        tree.
615
 
 
616
 
        There is no guarantee that all paths are in sorted order: the
617
 
        requirement to expand the search due to renames may result in children
618
 
        that should be found early being found late in the search, after
619
 
        lexically later results have been returned.
620
 
        :param require_versioned: Raise errors.PathsNotVersionedError if a
621
 
            path in the specific_files list is not versioned in one of
622
 
            source, target or extra_trees.
623
 
        :param want_unversioned: Should unversioned files be returned in the
624
 
            output. An unversioned file is defined as one with (False, False)
625
 
            for the versioned pair.
626
 
        """
627
 
        result = []
628
 
        lookup_trees = [self.source]
629
 
        if extra_trees:
630
 
             lookup_trees.extend(extra_trees)
631
 
        specific_file_ids = self.target.paths2ids(specific_files,
632
 
            lookup_trees, require_versioned=require_versioned)
633
 
        if want_unversioned:
634
 
            all_unversioned = sorted([(p.split('/'), p) for p in self.target.extras()
635
 
                if not specific_files or
636
 
                    osutils.is_inside_any(specific_files, p)])
637
 
            all_unversioned = deque(all_unversioned)
638
 
        else:
639
 
            all_unversioned = deque()
640
 
        to_paths = {}
641
 
        from_entries_by_dir = list(self.source.inventory.iter_entries_by_dir(
642
 
            specific_file_ids=specific_file_ids))
643
 
        from_data = dict((e.file_id, (p, e)) for p, e in from_entries_by_dir)
644
 
        to_entries_by_dir = list(self.target.inventory.iter_entries_by_dir(
645
 
            specific_file_ids=specific_file_ids))
646
 
        num_entries = len(from_entries_by_dir) + len(to_entries_by_dir)
647
 
        entry_count = 0
648
 
        # the unversioned path lookup only occurs on real trees - where there 
649
 
        # can be extras. So the fake_entry is solely used to look up
650
 
        # executable it values when execute is not supported.
651
 
        fake_entry = InventoryFile('unused', 'unused', 'unused')
652
 
        for to_path, to_entry in to_entries_by_dir:
653
 
            while all_unversioned and all_unversioned[0][0] < to_path.split('/'):
654
 
                unversioned_path = all_unversioned.popleft()
655
 
                to_kind, to_executable, to_stat = \
656
 
                    self.target._comparison_data(fake_entry, unversioned_path[1])
657
 
                yield (None, (None, unversioned_path[1]), True, (False, False),
658
 
                    (None, None),
659
 
                    (None, unversioned_path[0][-1]),
660
 
                    (None, to_kind),
661
 
                    (None, to_executable))
662
 
            file_id = to_entry.file_id
663
 
            to_paths[file_id] = to_path
664
 
            entry_count += 1
665
 
            changed_content = False
666
 
            from_path, from_entry = from_data.get(file_id, (None, None))
667
 
            from_versioned = (from_entry is not None)
668
 
            if from_entry is not None:
669
 
                from_versioned = True
670
 
                from_name = from_entry.name
671
 
                from_parent = from_entry.parent_id
672
 
                from_kind, from_executable, from_stat = \
673
 
                    self.source._comparison_data(from_entry, from_path)
674
 
                entry_count += 1
675
 
            else:
676
 
                from_versioned = False
677
 
                from_kind = None
678
 
                from_parent = None
679
 
                from_name = None
680
 
                from_executable = None
681
 
            versioned = (from_versioned, True)
682
 
            to_kind, to_executable, to_stat = \
683
 
                self.target._comparison_data(to_entry, to_path)
684
 
            kind = (from_kind, to_kind)
685
 
            if kind[0] != kind[1]:
686
 
                changed_content = True
687
 
            elif from_kind == 'file':
688
 
                from_size = self.source._file_size(from_entry, from_stat)
689
 
                to_size = self.target._file_size(to_entry, to_stat)
690
 
                if from_size != to_size:
691
 
                    changed_content = True
692
 
                elif (self.source.get_file_sha1(file_id, from_path, from_stat) !=
693
 
                    self.target.get_file_sha1(file_id, to_path, to_stat)):
694
 
                    changed_content = True
695
 
            elif from_kind == 'symlink':
696
 
                if (self.source.get_symlink_target(file_id) !=
697
 
                    self.target.get_symlink_target(file_id)):
698
 
                    changed_content = True
699
 
                elif from_kind == 'tree-reference':
700
 
                    if (self.source.get_reference_revision(file_id, from_path)
701
 
                        != self.target.get_reference_revision(file_id, to_path)):
702
 
                        changed_content = True 
703
 
            parent = (from_parent, to_entry.parent_id)
704
 
            name = (from_name, to_entry.name)
705
 
            executable = (from_executable, to_executable)
706
 
            if pb is not None:
707
 
                pb.update('comparing files', entry_count, num_entries)
708
 
            if (changed_content is not False or versioned[0] != versioned[1]
709
 
                or parent[0] != parent[1] or name[0] != name[1] or 
710
 
                executable[0] != executable[1] or include_unchanged):
711
 
                yield (file_id, (from_path, to_path), changed_content,
712
 
                    versioned, parent, name, kind, executable)
713
 
 
714
 
        while all_unversioned:
715
 
            # yield any trailing unversioned paths
716
 
            unversioned_path = all_unversioned.popleft()
717
 
            to_kind, to_executable, to_stat = \
718
 
                self.target._comparison_data(fake_entry, unversioned_path[1])
719
 
            yield (None, (None, unversioned_path[1]), True, (False, False),
720
 
                (None, None),
721
 
                (None, unversioned_path[0][-1]),
722
 
                (None, to_kind),
723
 
                (None, to_executable))
724
 
 
725
 
        def get_to_path(to_entry):
726
 
            if to_entry.parent_id is None:
727
 
                to_path = '' # the root
728
 
            else:
729
 
                if to_entry.parent_id not in to_paths:
730
 
                    # recurse up
731
 
                    return get_to_path(self.target.inventory[to_entry.parent_id])
732
 
                to_path = osutils.pathjoin(to_paths[to_entry.parent_id],
733
 
                                           to_entry.name)
734
 
            to_paths[to_entry.file_id] = to_path
735
 
            return to_path
736
 
 
737
 
        for path, from_entry in from_entries_by_dir:
738
 
            file_id = from_entry.file_id
739
 
            if file_id in to_paths:
740
 
                # already returned
741
 
                continue
742
 
            if not file_id in self.target.inventory:
743
 
                # common case - paths we have not emitted are not present in
744
 
                # target.
745
 
                to_path = None
746
 
            else:
747
 
                to_path = get_to_path(self.target.inventory[file_id])
748
 
            entry_count += 1
749
 
            if pb is not None:
750
 
                pb.update('comparing files', entry_count, num_entries)
751
 
            versioned = (True, False)
752
 
            parent = (from_entry.parent_id, None)
753
 
            name = (from_entry.name, None)
754
 
            from_kind, from_executable, stat_value = \
755
 
                self.source._comparison_data(from_entry, path)
756
 
            kind = (from_kind, None)
757
 
            executable = (from_executable, None)
758
 
            changed_content = True
759
 
            # the parent's path is necessarily known at this point.
760
 
            yield(file_id, (path, to_path), changed_content, versioned, parent,
761
 
                  name, kind, executable)
762
 
 
763
 
 
764
 
# This was deprecated before 0.12, but did not have an official warning
765
 
@symbol_versioning.deprecated_function(symbol_versioning.zero_twelve)
766
 
def RevisionTree(*args, **kwargs):
767
 
    """RevisionTree has moved to bzrlib.revisiontree.RevisionTree()
768
 
 
769
 
    Accessing it as bzrlib.tree.RevisionTree has been deprecated as of
770
 
    bzr 0.12.
771
 
    """
772
 
    from bzrlib.revisiontree import RevisionTree as _RevisionTree
773
 
    return _RevisionTree(*args, **kwargs)
774
 
 
775
 
 
 
430
            specific_file_ids, include_root)