1# Copyright (C) 2005-2011 Canonical Ltd
2#
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.
7#
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.
12#
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17"""Tree classes, representing directory at point in time.
18"""
19
20from . import (
21    errors,
22    lock,
23    osutils,
24    revision as _mod_revision,
25    trace,
26    )
27from .inter import InterObject
28
29
30class FileTimestampUnavailable(errors.BzrError):
31
32    _fmt = "The filestamp for %(path)s is not available."
33
34    internal_error = True
35
36    def __init__(self, path):
37        self.path = path
38
39
40class MissingNestedTree(errors.BzrError):
41
42    _fmt = "The nested tree for %(path)s can not be resolved."""
43
44    def __init__(self, path):
45        self.path = path
46
47
48class TreeEntry(object):
49    """An entry that implements the minimum interface used by commands.
50    """
51
52    __slots__ = []
53
54    def __eq__(self, other):
55        # yes, this is ugly, TODO: best practice __eq__ style.
56        return (isinstance(other, TreeEntry)
57                and other.__class__ == self.__class__)
58
59    kind = None
60
61    def kind_character(self):
62        return "???"
63
64    def is_unmodified(self, other):
65        """Does this entry reference the same entry?
66
67        This is mostly the same as __eq__, but returns False
68        for entries without enough information (i.e. revision is None)
69        """
70        return False
71
72
73class TreeDirectory(TreeEntry):
74    """See TreeEntry. This is a directory in a working tree."""
75
76    __slots__ = []
77
78    kind = 'directory'
79
80    def kind_character(self):
81        return "/"
82
83
84class TreeFile(TreeEntry):
85    """See TreeEntry. This is a regular file in a working tree."""
86
87    __slots__ = []
88
89    kind = 'file'
90
91    def kind_character(self):
92        return ''
93
94
95class TreeLink(TreeEntry):
96    """See TreeEntry. This is a symlink in a working tree."""
97
98    __slots__ = []
99
100    kind = 'symlink'
101
102    def kind_character(self):
103        return ''
104
105
106class TreeReference(TreeEntry):
107    """See TreeEntry. This is a reference to a nested tree in a working tree."""
108
109    __slots__ = []
110
111    kind = 'tree-reference'
112
113    def kind_character(self):
114        return '+'
115
116
117class TreeChange(object):
118    """Describes the changes between the same item in two different trees."""
119
120    __slots__ = ['path', 'changed_content', 'versioned',
121                 'name', 'kind', 'executable', 'copied']
122
123    def __init__(self, path, changed_content, versioned,
124                 name, kind, executable, copied=False):
125        self.path = path
126        self.changed_content = changed_content
127        self.versioned = versioned
128        self.name = name
129        self.kind = kind
130        self.executable = executable
131        self.copied = copied
132
133    def __repr__(self):
134        return "%s%r" % (self.__class__.__name__, self._as_tuple())
135
136    def _as_tuple(self):
137        return (self.path, self.changed_content, self.versioned,
138                self.name, self.kind, self.executable, self.copied)
139
140    def __eq__(self, other):
141        if isinstance(other, TreeChange):
142            return self._as_tuple() == other._as_tuple()
143        if isinstance(other, tuple):
144            return self._as_tuple() == other
145        return False
146
147    def __lt__(self, other):
148        return self._as_tuple() < other._as_tuple()
149
150    def meta_modified(self):
151        if self.versioned == (True, True):
152            return (self.executable[0] != self.executable[1])
153        return False
154
155    @property
156    def renamed(self):
157        return (
158            not self.copied and
159            None not in self.name and
160            self.path[0] != self.path[1])
161
162    def is_reparented(self):
163        return os.path.dirname(self.path[0]) != os.path.dirname(self.path[1])
164
165    def discard_new(self):
166        return self.__class__(
167            (self.path[0], None), self.changed_content,
168            (self.versioned[0], None),
169            (self.name[0], None), (self.kind[0], None),
170            (self.executable[0], None),
171            copied=False)
172
173
174class Tree(object):
175    """Abstract file tree.
176
177    There are several subclasses:
178
179    * `WorkingTree` exists as files on disk editable by the user.
180
181    * `RevisionTree` is a tree as recorded at some point in the past.
182
183    Trees can be compared, etc, regardless of whether they are working
184    trees or versioned trees.
185    """
186
187    def supports_rename_tracking(self):
188        """Whether this tree supports rename tracking.
189
190        This defaults to True, but some implementations may want to override
191        it.
192        """
193        return True
194
195    def has_versioned_directories(self):
196        """Whether this tree can contain explicitly versioned directories.
197
198        This defaults to True, but some implementations may want to override
199        it.
200        """
201        return True
202
203    def supports_symlinks(self):
204        """Does this tree support symbolic links?
205        """
206        return osutils.has_symlinks()
207
208    def changes_from(self, other, want_unchanged=False, specific_files=None,
209                     extra_trees=None, require_versioned=False, include_root=False,
210                     want_unversioned=False):
211        """Return a TreeDelta of the changes from other to this tree.
212
213        :param other: A tree to compare with.
214        :param specific_files: An optional list of file paths to restrict the
215            comparison to. When mapping filenames to ids, all matches in all
216            trees (including optional extra_trees) are used, and all children of
217            matched directories are included.
218        :param want_unchanged: An optional boolean requesting the inclusion of
219            unchanged entries in the result.
220        :param extra_trees: An optional list of additional trees to use when
221            mapping the contents of specific_files (paths) to their identities.
222        :param require_versioned: An optional boolean (defaults to False). When
223            supplied and True all the 'specific_files' must be versioned, or
224            a PathsNotVersionedError will be thrown.
225        :param want_unversioned: Scan for unversioned paths.
226
227        The comparison will be performed by an InterTree object looked up on
228        self and other.
229        """
230        # Martin observes that Tree.changes_from returns a TreeDelta and this
231        # may confuse people, because the class name of the returned object is
232        # a synonym of the object referenced in the method name.
233        return InterTree.get(other, self).compare(
234            want_unchanged=want_unchanged,
235            specific_files=specific_files,
236            extra_trees=extra_trees,
237            require_versioned=require_versioned,
238            include_root=include_root,
239            want_unversioned=want_unversioned,
240            )
241
242    def iter_changes(self, from_tree, include_unchanged=False,
243                     specific_files=None, pb=None, extra_trees=None,
244                     require_versioned=True, want_unversioned=False):
245        """See InterTree.iter_changes"""
246        intertree = InterTree.get(from_tree, self)
247        return intertree.iter_changes(include_unchanged, specific_files, pb,
248                                      extra_trees, require_versioned,
249                                      want_unversioned=want_unversioned)
250
251    def conflicts(self):
252        """Get a list of the conflicts in the tree.
253
254        Each conflict is an instance of breezy.conflicts.Conflict.
255        """
256        from . import conflicts as _mod_conflicts
257        return _mod_conflicts.ConflictList()
258
259    def extras(self):
260        """For trees that can have unversioned files, return all such paths."""
261        return []
262
263    def get_parent_ids(self):
264        """Get the parent ids for this tree.
265
266        :return: a list of parent ids. [] is returned to indicate
267        a tree with no parents.
268        :raises: BzrError if the parents are not known.
269        """
270        raise NotImplementedError(self.get_parent_ids)
271
272    def has_filename(self, filename):
273        """True if the tree has given filename."""
274        raise NotImplementedError(self.has_filename)
275
276    def is_ignored(self, filename):
277        """Check whether the filename is ignored by this tree.
278
279        :param filename: The relative filename within the tree.
280        :return: True if the filename is ignored.
281        """
282        return False
283
284    def all_file_ids(self):
285        """Iterate through all file ids, including ids for missing files."""
286        raise NotImplementedError(self.all_file_ids)
287
288    def all_versioned_paths(self):
289        """Iterate through all paths, including paths for missing files."""
290        raise NotImplementedError(self.all_versioned_paths)
291
292    def id2path(self, file_id, recurse='down'):
293        """Return the path for a file id.
294
295        :raises NoSuchId:
296        """
297        raise NotImplementedError(self.id2path)
298
299    def iter_entries_by_dir(self, specific_files=None, recurse_nested=False):
300        """Walk the tree in 'by_dir' order.
301
302        This will yield each entry in the tree as a (path, entry) tuple.
303        The order that they are yielded is:
304
305        Directories are walked in a depth-first lexicographical order,
306        however, whenever a directory is reached, all of its direct child
307        nodes are yielded in  lexicographical order before yielding the
308        grandchildren.
309
310        For example, in the tree::
311
312           a/
313             b/
314               c
315             d/
316               e
317           f/
318             g
319
320        The yield order (ignoring root) would be::
321
322          a, f, a/b, a/d, a/b/c, a/d/e, f/g
323
324        If recurse_nested is enabled then nested trees are included as if
325        they were a part of the tree. If is disabled then TreeReference
326        objects (without any children) are yielded.
327        """
328        raise NotImplementedError(self.iter_entries_by_dir)
329
330    def iter_child_entries(self, path):
331        """Iterate over the children of a directory or tree reference.
332
333        :param path: Path of the directory
334        :raise NoSuchFile: When the path does not exist
335        :return: Iterator over entries in the directory
336        """
337        raise NotImplementedError(self.iter_child_entries)
338
339    def list_files(self, include_root=False, from_dir=None, recursive=True,
340                   recurse_nested=False):
341        """List all files in this tree.
342
343        :param include_root: Whether to include the entry for the tree root
344        :param from_dir: Directory under which to list files
345        :param recursive: Whether to list files recursively
346        :param recurse_nested: enter nested trees
347        :return: iterator over tuples of
348            (path, versioned, kind, inventory entry)
349        """
350        raise NotImplementedError(self.list_files)
351
352    def iter_references(self):
353        if self.supports_tree_reference():
354            for path, entry in self.iter_entries_by_dir():
355                if entry.kind == 'tree-reference':
356                    yield path
357
358    def get_containing_nested_tree(self, path):
359        """Find the nested tree that contains a path.
360
361        :return: tuple with (nested tree and path inside the nested tree)
362        """
363        for nested_path in self.iter_references():
364            nested_path += '/'
365            if path.startswith(nested_path):
366                nested_tree = self.get_nested_tree(nested_path)
367                return nested_tree, path[len(nested_path):]
368        else:
369            return None, None
370
371    def get_nested_tree(self, path):
372        """Open the nested tree at the specified path.
373
374        :param path: Path from which to resolve tree reference.
375        :return: A Tree object for the nested tree
376        :raise MissingNestedTree: If the nested tree can not be resolved
377        """
378        raise NotImplementedError(self.get_nested_tree)
379
380    def kind(self, path):
381        raise NotImplementedError("Tree subclass %s must implement kind"
382                                  % self.__class__.__name__)
383
384    def stored_kind(self, path):
385        """File kind stored for this path.
386
387        May not match kind on disk for working trees.  Always available
388        for versioned files, even when the file itself is missing.
389        """
390        return self.kind(path)
391
392    def path_content_summary(self, path):
393        """Get a summary of the information about path.
394
395        All the attributes returned are for the canonical form, not the
396        convenient form (if content filters are in use.)
397
398        :param path: A relative path within the tree.
399        :return: A tuple containing kind, size, exec, sha1-or-link.
400            Kind is always present (see tree.kind()).
401            size is present if kind is file and the size of the
402                canonical form can be cheaply determined, None otherwise.
403            exec is None unless kind is file and the platform supports the 'x'
404                bit.
405            sha1-or-link is the link target if kind is symlink, or the sha1 if
406                it can be obtained without reading the file.
407        """
408        raise NotImplementedError(self.path_content_summary)
409
410    def get_reference_revision(self, path, branch=None):
411        raise NotImplementedError("Tree subclass %s must implement "
412                                  "get_reference_revision"
413                                  % self.__class__.__name__)
414
415    def _comparison_data(self, entry, path):
416        """Return a tuple of kind, executable, stat_value for a file.
417
418        entry may be None if there is no inventory entry for the file, but
419        path must always be supplied.
420
421        kind is None if there is no file present (even if an inventory id is
422        present).  executable is False for non-file entries.
423        """
424        raise NotImplementedError(self._comparison_data)
425
426    def get_file(self, path):
427        """Return a file object for the file path in the tree.
428        """
429        raise NotImplementedError(self.get_file)
430
431    def get_file_with_stat(self, path):
432        """Get a file handle and stat object for path.
433
434        The default implementation returns (self.get_file, None) for backwards
435        compatibility.
436
437        :param path: The path of the file.
438        :return: A tuple (file_handle, stat_value_or_None). If the tree has
439            no stat facility, or need for a stat cache feedback during commit,
440            it may return None for the second element of the tuple.
441        """
442        return (self.get_file(path), None)
443
444    def get_file_text(self, path):
445        """Return the byte content of a file.
446
447        :param path: The path of the file.
448
449        :returns: A single byte string for the whole file.
450        """
451        with self.get_file(path) as my_file:
452            return my_file.read()
453
454    def get_file_lines(self, path):
455        """Return the content of a file, as lines.
456
457        :param path: The path of the file.
458        """
459        return osutils.split_lines(self.get_file_text(path))
460
461    def get_file_verifier(self, path, stat_value=None):
462        """Return a verifier for a file.
463
464        The default implementation returns a sha1.
465
466        :param path: The path that this file can be found at.
467            These must point to the same object.
468        :param stat_value: Optional stat value for the object
469        :return: Tuple with verifier name and verifier data
470        """
471        return ("SHA1", self.get_file_sha1(path, stat_value=stat_value))
472
473    def get_file_sha1(self, path, stat_value=None):
474        """Return the SHA1 file for a file.
475
476        :note: callers should use get_file_verifier instead
477            where possible, as the underlying repository implementation may
478            have quicker access to a non-sha1 verifier.
479
480        :param path: The path that this file can be found at.
481        :param stat_value: Optional stat value for the object
482        """
483        raise NotImplementedError(self.get_file_sha1)
484
485    def get_file_mtime(self, path):
486        """Return the modification time for a file.
487
488        :param path: The path that this file can be found at.
489        """
490        raise NotImplementedError(self.get_file_mtime)
491
492    def get_file_size(self, path):
493        """Return the size of a file in bytes.
494
495        This applies only to regular files.  If invoked on directories or
496        symlinks, it will return None.
497        """
498        raise NotImplementedError(self.get_file_size)
499
500    def is_executable(self, path):
501        """Check if a file is executable.
502
503        :param path: The path that this file can be found at.
504        """
505        raise NotImplementedError(self.is_executable)
506
507    def iter_files_bytes(self, desired_files):
508        """Iterate through file contents.
509
510        Files will not necessarily be returned in the order they occur in
511        desired_files.  No specific order is guaranteed.
512
513        Yields pairs of identifier, bytes_iterator.  identifier is an opaque
514        value supplied by the caller as part of desired_files.  It should
515        uniquely identify the file version in the caller's context.  (Examples:
516        an index number or a TreeTransform trans_id.)
517
518        bytes_iterator is an iterable of bytestrings for the file.  The
519        kind of iterable and length of the bytestrings are unspecified, but for
520        this implementation, it is a tuple containing a single bytestring with
521        the complete text of the file.
522
523        :param desired_files: a list of (path, identifier) pairs
524        """
525        for path, identifier in desired_files:
526            # We wrap the string in a tuple so that we can return an iterable
527            # of bytestrings.  (Technically, a bytestring is also an iterable
528            # of bytestrings, but iterating through each character is not
529            # performant.)
530            cur_file = (self.get_file_text(path),)
531            yield identifier, cur_file
532
533    def get_symlink_target(self, path):
534        """Get the target for a given path.
535
536        It is assumed that the caller already knows that path is referencing
537        a symlink.
538        :param path: The path of the file.
539        :return: The path the symlink points to.
540        """
541        raise NotImplementedError(self.get_symlink_target)
542
543    def annotate_iter(self, path,
544                      default_revision=_mod_revision.CURRENT_REVISION):
545        """Return an iterator of revision_id, line tuples.
546
547        For working trees (and mutable trees in general), the special
548        revision_id 'current:' will be used for lines that are new in this
549        tree, e.g. uncommitted changes.
550        :param path: The file to produce an annotated version from
551        :param default_revision: For lines that don't match a basis, mark them
552            with this revision id. Not all implementations will make use of
553            this value.
554        """
555        raise NotImplementedError(self.annotate_iter)
556
557    def path2id(self, path):
558        """Return the id for path in this tree."""
559        raise NotImplementedError(self.path2id)
560
561    def is_versioned(self, path):
562        """Check whether path is versioned.
563
564        :param path: Path to check
565        :return: boolean
566        """
567        return self.path2id(path) is not None
568
569    def find_related_paths_across_trees(self, paths, trees=[],
570                                        require_versioned=True):
571        """Find related paths in tree corresponding to specified filenames in any
572        of `lookup_trees`.
573
574        All matches in all trees will be used, and all children of matched
575        directories will be used.
576
577        :param paths: The filenames to find related paths for (if None, returns
578            None)
579        :param trees: The trees to find file_ids within
580        :param require_versioned: if true, all specified filenames must occur in
581            at least one tree.
582        :return: a set of paths for the specified filenames and their children
583            in `tree`
584        """
585        raise NotImplementedError(self.find_related_paths_across_trees)
586
587    def lock_read(self):
588        """Lock this tree for multiple read only operations.
589
590        :return: A breezy.lock.LogicalLockResult.
591        """
592        return lock.LogicalLockResult(self.unlock)
593
594    def revision_tree(self, revision_id):
595        """Obtain a revision tree for the revision revision_id.
596
597        The intention of this method is to allow access to possibly cached
598        tree data. Implementors of this method should raise NoSuchRevision if
599        the tree is not locally available, even if they could obtain the
600        tree via a repository or some other means. Callers are responsible
601        for finding the ultimate source for a revision tree.
602
603        :param revision_id: The revision_id of the requested tree.
604        :return: A Tree.
605        :raises: NoSuchRevision if the tree cannot be obtained.
606        """
607        raise errors.NoSuchRevisionInTree(self, revision_id)
608
609    def unknowns(self):
610        """What files are present in this tree and unknown.
611
612        :return: an iterator over the unknown files.
613        """
614        return iter([])
615
616    def unlock(self):
617        pass
618
619    def filter_unversioned_files(self, paths):
620        """Filter out paths that are versioned.
621
622        :return: set of paths.
623        """
624        # NB: we specifically *don't* call self.has_filename, because for
625        # WorkingTrees that can indicate files that exist on disk but that
626        # are not versioned.
627        return set(p for p in paths if not self.is_versioned(p))
628
629    def walkdirs(self, prefix=""):
630        """Walk the contents of this tree from path down.
631
632        This yields all the data about the contents of a directory at a time.
633        After each directory has been yielded, if the caller has mutated the
634        list to exclude some directories, they are then not descended into.
635
636        The data yielded is of the form:
637        (directory-relpath,
638        [(relpath, basename, kind, lstat, path_from_tree_root,
639          versioned_kind), ...]),
640         - directory-path-from-root is the containing dirs path from /
641         - relpath is the relative path within the subtree being walked.
642         - basename is the basename
643         - kind is the kind of the file now. If unknonwn then the file is not
644           present within the tree - but it may be recorded as versioned. See
645           versioned_kind.
646         - lstat is the stat data *if* the file was statted.
647         - path_from_tree_root is the path from the root of the tree.
648         - versioned_kind is the kind of the file as last recorded in the
649           versioning system. If 'unknown' the file is not versioned.
650        One of 'kind' and 'versioned_kind' must not be 'unknown'.
651
652        :param prefix: Start walking from prefix within the tree rather than
653        at the root. This allows one to walk a subtree but get paths that are
654        relative to a tree rooted higher up.
655        :return: an iterator over the directory data.
656        """
657        raise NotImplementedError(self.walkdirs)
658
659    def supports_content_filtering(self):
660        return False
661
662    def _content_filter_stack(self, path=None):
663        """The stack of content filters for a path if filtering is supported.
664
665        Readers will be applied in first-to-last order.
666        Writers will be applied in last-to-first order.
667        Either the path or the file-id needs to be provided.
668
669        :param path: path relative to the root of the tree
670            or None if unknown
671        :return: the list of filters - [] if there are none
672        """
673        from . import debug, filters
674        filter_pref_names = filters._get_registered_names()
675        if len(filter_pref_names) == 0:
676            return []
677        prefs = next(self.iter_search_rules([path], filter_pref_names))
678        stk = filters._get_filter_stack_for(prefs)
679        if 'filters' in debug.debug_flags:
680            trace.note("*** {0} content-filter: {1} => {2!r}").format(path, prefs, stk)
681        return stk
682
683    def _content_filter_stack_provider(self):
684        """A function that returns a stack of ContentFilters.
685
686        The function takes a path (relative to the top of the tree) and a
687        file-id as parameters.
688
689        :return: None if content filtering is not supported by this tree.
690        """
691        if self.supports_content_filtering():
692            return self._content_filter_stack
693        else:
694            return None
695
696    def iter_search_rules(self, path_names, pref_names=None,
697                          _default_searcher=None):
698        """Find the preferences for filenames in a tree.
699
700        :param path_names: an iterable of paths to find attributes for.
701          Paths are given relative to the root of the tree.
702        :param pref_names: the list of preferences to lookup - None for all
703        :param _default_searcher: private parameter to assist testing - don't use
704        :return: an iterator of tuple sequences, one per path-name.
705          See _RulesSearcher.get_items for details on the tuple sequence.
706        """
707        from . import rules
708        if _default_searcher is None:
709            _default_searcher = rules._per_user_searcher
710        searcher = self._get_rules_searcher(_default_searcher)
711        if searcher is not None:
712            if pref_names is not None:
713                for path in path_names:
714                    yield searcher.get_selected_items(path, pref_names)
715            else:
716                for path in path_names:
717                    yield searcher.get_items(path)
718
719    def _get_rules_searcher(self, default_searcher):
720        """Get the RulesSearcher for this tree given the default one."""
721        searcher = default_searcher
722        return searcher
723
724    def archive(self, format, name, root='', subdir=None,
725                force_mtime=None):
726        """Create an archive of this tree.
727
728        :param format: Format name (e.g. 'tar')
729        :param name: target file name
730        :param root: Root directory name (or None)
731        :param subdir: Subdirectory to export (or None)
732        :return: Iterator over archive chunks
733        """
734        from .archive import create_archive
735        with self.lock_read():
736            return create_archive(format, self, name, root,
737                                  subdir, force_mtime=force_mtime)
738
739    @classmethod
740    def versionable_kind(cls, kind):
741        """Check if this tree support versioning a specific file kind."""
742        return (kind in ('file', 'directory', 'symlink', 'tree-reference'))
743
744    def preview_transform(self, pb=None):
745        """Obtain a transform object."""
746        raise NotImplementedError(self.preview_transform)
747
748
749class InterTree(InterObject):
750    """This class represents operations taking place between two Trees.
751
752    Its instances have methods like 'compare' and contain references to the
753    source and target trees these operations are to be carried out on.
754
755    Clients of breezy should not need to use InterTree directly, rather they
756    should use the convenience methods on Tree such as 'Tree.compare()' which
757    will pass through to InterTree as appropriate.
758    """
759
760    # Formats that will be used to test this InterTree. If both are
761    # None, this InterTree will not be tested (e.g. because a complex
762    # setup is required)
763    _matching_from_tree_format = None
764    _matching_to_tree_format = None
765
766    _optimisers = []
767
768    @classmethod
769    def is_compatible(kls, source, target):
770        # The default implementation is naive and uses the public API, so
771        # it works for all trees.
772        return True
773
774    def compare(self, want_unchanged=False, specific_files=None,
775                extra_trees=None, require_versioned=False, include_root=False,
776                want_unversioned=False):
777        """Return the changes from source to target.
778
779        :return: A TreeDelta.
780        :param specific_files: An optional list of file paths to restrict the
781            comparison to. When mapping filenames to ids, all matches in all
782            trees (including optional extra_trees) are used, and all children of
783            matched directories are included.
784        :param want_unchanged: An optional boolean requesting the inclusion of
785            unchanged entries in the result.
786        :param extra_trees: An optional list of additional trees to use when
787            mapping the contents of specific_files (paths) to file_ids.
788        :param require_versioned: An optional boolean (defaults to False). When
789            supplied and True all the 'specific_files' must be versioned, or
790            a PathsNotVersionedError will be thrown.
791        :param want_unversioned: Scan for unversioned paths.
792        """
793        from . import delta
794        trees = (self.source,)
795        if extra_trees is not None:
796            trees = trees + tuple(extra_trees)
797        with self.lock_read():
798            return delta._compare_trees(self.source, self.target, want_unchanged,
799                                        specific_files, include_root, extra_trees=extra_trees,
800                                        require_versioned=require_versioned,
801                                        want_unversioned=want_unversioned)
802
803    def iter_changes(self, include_unchanged=False,
804                     specific_files=None, pb=None, extra_trees=[],
805                     require_versioned=True, want_unversioned=False):
806        """Generate an iterator of changes between trees.
807
808        A tuple is returned:
809        (file_id, (path_in_source, path_in_target),
810         changed_content, versioned, parent, name, kind,
811         executable)
812
813        Changed_content is True if the file's content has changed.  This
814        includes changes to its kind, and to a symlink's target.
815
816        versioned, parent, name, kind, executable are tuples of (from, to).
817        If a file is missing in a tree, its kind is None.
818
819        Iteration is done in parent-to-child order, relative to the target
820        tree.
821
822        There is no guarantee that all paths are in sorted order: the
823        requirement to expand the search due to renames may result in children
824        that should be found early being found late in the search, after
825        lexically later results have been returned.
826        :param require_versioned: Raise errors.PathsNotVersionedError if a
827            path in the specific_files list is not versioned in one of
828            source, target or extra_trees.
829        :param specific_files: An optional list of file paths to restrict the
830            comparison to. When mapping filenames to ids, all matches in all
831            trees (including optional extra_trees) are used, and all children
832            of matched directories are included. The parents in the target tree
833            of the specific files up to and including the root of the tree are
834            always evaluated for changes too.
835        :param want_unversioned: Should unversioned files be returned in the
836            output. An unversioned file is defined as one with (False, False)
837            for the versioned pair.
838        """
839        raise NotImplementedError(self.iter_changes)
840
841    def file_content_matches(
842            self, source_path, target_path,
843            source_stat=None, target_stat=None):
844        """Check if two files are the same in the source and target trees.
845
846        This only checks that the contents of the files are the same,
847        it does not touch anything else.
848
849        :param source_path: Path of the file in the source tree
850        :param target_path: Path of the file in the target tree
851        :param source_stat: Optional stat value of the file in the source tree
852        :param target_stat: Optional stat value of the file in the target tree
853        :return: Boolean indicating whether the files have the same contents
854        """
855        with self.lock_read():
856            source_verifier_kind, source_verifier_data = (
857                self.source.get_file_verifier(source_path, source_stat))
858            target_verifier_kind, target_verifier_data = (
859                self.target.get_file_verifier(
860                    target_path, target_stat))
861            if source_verifier_kind == target_verifier_kind:
862                return (source_verifier_data == target_verifier_data)
863            # Fall back to SHA1 for now
864            if source_verifier_kind != "SHA1":
865                source_sha1 = self.source.get_file_sha1(
866                    source_path, source_stat)
867            else:
868                source_sha1 = source_verifier_data
869            if target_verifier_kind != "SHA1":
870                target_sha1 = self.target.get_file_sha1(
871                    target_path, target_stat)
872            else:
873                target_sha1 = target_verifier_data
874            return (source_sha1 == target_sha1)
875
876    def find_target_path(self, path, recurse='none'):
877        """Find target tree path.
878
879        :param path: Path to search for (exists in source)
880        :return: path in target, or None if there is no equivalent path.
881        :raise NoSuchFile: If the path doesn't exist in source
882        """
883        raise NotImplementedError(self.find_target_path)
884
885    def find_source_path(self, path, recurse='none'):
886        """Find the source tree path.
887
888        :param path: Path to search for (exists in target)
889        :return: path in source, or None if there is no equivalent path.
890        :raise NoSuchFile: if the path doesn't exist in target
891        """
892        raise NotImplementedError(self.find_source_path)
893
894    def find_target_paths(self, paths, recurse='none'):
895        """Find target tree paths.
896
897        :param paths: Iterable over paths in target to search for
898        :return: Dictionary mapping from source paths to paths in target , or
899            None if there is no equivalent path.
900        """
901        ret = {}
902        for path in paths:
903            ret[path] = self.find_target_path(path, recurse=recurse)
904        return ret
905
906    def find_source_paths(self, paths, recurse='none'):
907        """Find source tree paths.
908
909        :param paths: Iterable over paths in target to search for
910        :return: Dictionary mapping from target paths to paths in source, or
911            None if there is no equivalent path.
912        """
913        ret = {}
914        for path in paths:
915            ret[path] = self.find_source_path(path, recurse=recurse)
916        return ret
917
918
919def find_previous_paths(from_tree, to_tree, paths, recurse='none'):
920    """Find previous tree paths.
921
922    :param from_tree: From tree
923    :param to_tree: To tree
924    :param paths: Iterable over paths in from_tree to search for
925    :return: Dictionary mapping from from_tree paths to paths in to_tree, or
926        None if there is no equivalent path.
927    """
928    return InterTree.get(to_tree, from_tree).find_source_paths(paths, recurse=recurse)
929
930
931def find_previous_path(from_tree, to_tree, path, recurse='none'):
932    """Find previous tree path.
933
934    :param from_tree: From tree
935    :param to_tree: To tree
936    :param path: Path to search for (exists in from_tree)
937    :return: path in to_tree, or None if there is no equivalent path.
938    :raise NoSuchFile: If the path doesn't exist in from_tree
939    """
940    return InterTree.get(to_tree, from_tree).find_source_path(
941        path, recurse=recurse)
942
943
944def get_canonical_path(tree, path, normalize):
945    """Find the canonical path of an item, ignoring case.
946
947    :param tree: Tree to traverse
948    :param path: Case-insensitive path to look up
949    :param normalize: Function to normalize a filename for comparison
950    :return: The canonical path
951    """
952    # go walkin...
953    cur_path = ''
954    bit_iter = iter(path.split("/"))
955    for elt in bit_iter:
956        lelt = normalize(elt)
957        new_path = None
958        try:
959            for child in tree.iter_child_entries(cur_path):
960                try:
961                    if child.name == elt:
962                        # if we found an exact match, we can stop now; if
963                        # we found an approximate match we need to keep
964                        # searching because there might be an exact match
965                        # later.
966                        new_path = osutils.pathjoin(cur_path, child.name)
967                        break
968                    elif normalize(child.name) == lelt:
969                        new_path = osutils.pathjoin(cur_path, child.name)
970                except errors.NoSuchId:
971                    # before a change is committed we can see this error...
972                    continue
973        except errors.NotADirectory:
974            pass
975        if new_path:
976            cur_path = new_path
977        else:
978            # got to the end of this directory and no entries matched.
979            # Return what matched so far, plus the rest as specified.
980            cur_path = osutils.pathjoin(cur_path, elt, *list(bit_iter))
981            break
982    return cur_path
983