bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 1
by mbp at sourcefrog import from baz patch-364 | 1 | #! /usr/bin/env python
 | 
| 2 | # -*- coding: UTF-8 -*-
 | |
| 3 | ||
| 4 | # This program is free software; you can redistribute it and/or modify
 | |
| 5 | # it under the terms of the GNU General Public License as published by
 | |
| 6 | # the Free Software Foundation; either version 2 of the License, or
 | |
| 7 | # (at your option) any later version.
 | |
| 8 | ||
| 9 | # This program is distributed in the hope that it will be useful,
 | |
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| 12 | # GNU General Public License for more details.
 | |
| 13 | ||
| 14 | # You should have received a copy of the GNU General Public License
 | |
| 15 | # along with this program; if not, write to the Free Software
 | |
| 16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
| 17 | ||
| 18 | from sets import Set | |
| 19 | ||
| 20 | from trace import mutter | |
| 21 | ||
| 22 | ||
| 23 | ||
| 24 | ||
| 25 | ||
| 26 | ||
| 27 | def diff_trees(old_tree, new_tree): | |
| 28 | """Compute diff between two trees. | |
| 29 | ||
| 30 |     They may be in different branches and may be working or historical
 | |
| 31 |     trees.
 | |
| 32 | ||
| 33 |     Yields a sequence of (state, id, old_name, new_name, kind).
 | |
| 34 |     Each filename and each id is listed only once.
 | |
| 35 |     """
 | |
| 36 | ||
| 37 |     ## TODO: Compare files before diffing; only mention those that have changed
 | |
| 38 | ||
| 39 |     ## TODO: Set nice names in the headers, maybe include diffstat
 | |
| 40 | ||
| 41 |     ## TODO: Perhaps make this a generator rather than using
 | |
| 42 |     ## a callback object?
 | |
| 43 | ||
| 44 |     ## TODO: Allow specifying a list of files to compare, rather than
 | |
| 45 |     ## doing the whole tree?  (Not urgent.)
 | |
| 46 | ||
| 47 |     ## TODO: Allow diffing any two inventories, not just the
 | |
| 48 |     ## current one against one.  We mgiht need to specify two
 | |
| 49 |     ## stores to look for the files if diffing two branches.  That
 | |
| 50 |     ## might imply this shouldn't be primarily a Branch method.
 | |
| 51 | ||
| 52 |     ## XXX: This doesn't report on unknown files; that can be done
 | |
| 53 |     ## from a separate method.
 | |
| 54 | ||
| 55 | old_it = old_tree.list_files() | |
| 56 | new_it = new_tree.list_files() | |
| 57 | ||
| 58 | def next(it): | |
| 59 | try: | |
| 60 | return it.next() | |
| 61 | except StopIteration: | |
| 62 | return None | |
| 63 | ||
| 64 | old_item = next(old_it) | |
| 65 | new_item = next(new_it) | |
| 66 | ||
| 67 |     # We step through the two sorted iterators in parallel, trying to
 | |
| 68 |     # keep them lined up.
 | |
| 69 | ||
| 70 | while (old_item != None) or (new_item != None): | |
| 71 |         # OK, we still have some remaining on both, but they may be
 | |
| 72 |         # out of step.        
 | |
| 73 | if old_item != None: | |
| 74 | old_name, old_class, old_kind, old_id = old_item | |
| 75 | else: | |
| 76 | old_name = None | |
| 77 | ||
| 78 | if new_item != None: | |
| 79 | new_name, new_class, new_kind, new_id = new_item | |
| 80 | else: | |
| 81 | new_name = None | |
| 82 | ||
| 83 | mutter(" diff pairwise %r" % (old_item,)) | |
| 84 | mutter(" %r" % (new_item,)) | |
| 85 | ||
| 86 | if old_item: | |
| 87 |             # can't handle the old tree being a WorkingTree
 | |
| 88 | assert old_class == 'V' | |
| 89 | ||
| 90 | if new_item and (new_class != 'V'): | |
| 91 | yield new_class, None, None, new_name, new_kind | |
| 92 | new_item = next(new_it) | |
| 93 | elif (not new_item) or (old_item and (old_name < new_name)): | |
| 94 | mutter(" extra entry in old-tree sequence") | |
| 95 | if new_tree.has_id(old_id): | |
| 96 |                 # will be mentioned as renamed under new name
 | |
| 97 |                 pass
 | |
| 98 | else: | |
| 99 | yield 'D', old_id, old_name, None, old_kind | |
| 100 | old_item = next(old_it) | |
| 101 | elif (not old_item) or (new_item and (new_name < old_name)): | |
| 102 | mutter(" extra entry in new-tree sequence") | |
| 103 | if old_tree.has_id(new_id): | |
| 104 | yield 'R', new_id, old_tree.id2path(new_id), new_name, new_kind | |
| 105 | else: | |
| 106 | yield 'A', new_id, None, new_name, new_kind | |
| 107 | new_item = next(new_it) | |
| 108 | elif old_id != new_id: | |
| 109 | assert old_name == new_name | |
| 110 |             # both trees have a file of this name, but it is not the
 | |
| 111 |             # same file.  in other words, the old filename has been
 | |
| 112 |             # overwritten by either a newly-added or a renamed file.
 | |
| 113 |             # (should we return something about the overwritten file?)
 | |
| 114 | if old_tree.has_id(new_id): | |
| 115 |                 # renaming, overlying a deleted file
 | |
| 116 | yield 'R', new_id, old_tree.id2path(new_id), new_name, new_kind | |
| 117 | else: | |
| 118 | yield 'A', new_id, None, new_name, new_kind | |
| 119 | ||
| 120 | new_item = next(new_it) | |
| 121 | old_item = next(old_it) | |
| 122 | else: | |
| 123 | assert old_id == new_id | |
| 178
by mbp at sourcefrog - Use a non-null file_id for the branch root directory. At the moment | 124 | assert old_id != None | 
| 1
by mbp at sourcefrog import from baz patch-364 | 125 | assert old_name == new_name | 
| 126 | assert old_kind == new_kind | |
| 127 | ||
| 128 | if old_kind == 'directory': | |
| 129 | yield '.', new_id, old_name, new_name, new_kind | |
| 130 | elif old_tree.get_file_size(old_id) != new_tree.get_file_size(old_id): | |
| 131 | mutter(" file size has changed, must be different") | |
| 132 | yield 'M', new_id, old_name, new_name, new_kind | |
| 133 | elif old_tree.get_file_sha1(old_id) == new_tree.get_file_sha1(old_id): | |
| 134 | mutter(" SHA1 indicates they're identical") | |
| 135 |                 ## assert compare_files(old_tree.get_file(i), new_tree.get_file(i))
 | |
| 136 | yield '.', new_id, old_name, new_name, new_kind | |
| 137 | else: | |
| 138 | mutter(" quick compare shows different") | |
| 139 | yield 'M', new_id, old_name, new_name, new_kind | |
| 140 | ||
| 141 | new_item = next(new_it) | |
| 142 | old_item = next(old_it) | |
| 143 | ||
| 144 |