/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
1
# -*- coding: UTF-8 -*-
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
from bzrlib.trace import mutter
18
19
class TreeDelta(object):
20
    """Describes changes from one tree to another.
21
22
    Contains four lists:
23
24
    added
25
        (path, id, kind)
26
    removed
27
        (path, id, kind)
28
    renamed
1398 by Robert Collins
integrate in Gustavos x-bit patch
29
        (oldpath, newpath, id, kind, text_modified, meta_modified)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
30
    modified
1398 by Robert Collins
integrate in Gustavos x-bit patch
31
        (path, id, kind, text_modified, meta_modified)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
32
    unchanged
33
        (path, id, kind)
34
35
    Each id is listed only once.
36
37
    Files that are both modified and renamed are listed only in
1092.2.6 by Robert Collins
symlink support updated to work
38
    renamed, with the text_modified flag true. The text_modified
39
    applies either to the the content of the file or the target of the
40
    symbolic link, depending of the kind of file.
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
41
42
    Files are only considered renamed if their name has changed or
43
    their parent directory has changed.  Renaming a directory
44
    does not count as renaming all its contents.
45
46
    The lists are normally sorted when the delta is created.
47
    """
48
    def __init__(self):
49
        self.added = []
50
        self.removed = []
51
        self.renamed = []
52
        self.modified = []
53
        self.unchanged = []
54
55
    def __eq__(self, other):
56
        if not isinstance(other, TreeDelta):
57
            return False
58
        return self.added == other.added \
59
               and self.removed == other.removed \
60
               and self.renamed == other.renamed \
61
               and self.modified == other.modified \
62
               and self.unchanged == other.unchanged
63
64
    def __ne__(self, other):
65
        return not (self == other)
66
67
    def __repr__(self):
68
        return "TreeDelta(added=%r, removed=%r, renamed=%r, modified=%r," \
69
            " unchanged=%r)" % (self.added, self.removed, self.renamed,
70
            self.modified, self.unchanged)
71
72
    def has_changed(self):
1189 by Martin Pool
- BROKEN: partial support for commit into weave
73
        return bool(self.modified
74
                    or self.added
75
                    or self.removed
76
                    or self.renamed)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
77
78
    def touches_file_id(self, file_id):
79
        """Return True if file_id is modified by this delta."""
80
        for l in self.added, self.removed, self.modified:
81
            for v in l:
82
                if v[1] == file_id:
83
                    return True
84
        for v in self.renamed:
85
            if v[2] == file_id:
86
                return True
87
        return False
88
            
89
90
    def show(self, to_file, show_ids=False, show_unchanged=False):
91
        def show_list(files):
1398 by Robert Collins
integrate in Gustavos x-bit patch
92
            for item in files:
93
                path, fid, kind = item[:3]
94
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
95
                if kind == 'directory':
96
                    path += '/'
97
                elif kind == 'symlink':
98
                    path += '@'
1398 by Robert Collins
integrate in Gustavos x-bit patch
99
100
                if len(item) == 5 and item[4]:
101
                    path += '*'
102
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
103
                if show_ids:
104
                    print >>to_file, '  %-30s %s' % (path, fid)
105
                else:
106
                    print >>to_file, ' ', path
107
            
108
        if self.removed:
109
            print >>to_file, 'removed:'
110
            show_list(self.removed)
111
                
112
        if self.added:
113
            print >>to_file, 'added:'
114
            show_list(self.added)
115
116
        if self.renamed:
117
            print >>to_file, 'renamed:'
1398 by Robert Collins
integrate in Gustavos x-bit patch
118
            for (oldpath, newpath, fid, kind,
119
                 text_modified, meta_modified) in self.renamed:
120
                if meta_modified:
121
                    newpath += '*'
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
122
                if show_ids:
123
                    print >>to_file, '  %s => %s %s' % (oldpath, newpath, fid)
124
                else:
125
                    print >>to_file, '  %s => %s' % (oldpath, newpath)
126
                    
127
        if self.modified:
128
            print >>to_file, 'modified:'
129
            show_list(self.modified)
130
            
131
        if show_unchanged and self.unchanged:
132
            print >>to_file, 'unchanged:'
133
            show_list(self.unchanged)
134
135
136
137
def compare_trees(old_tree, new_tree, want_unchanged=False, specific_files=None):
138
    """Describe changes from one tree to another.
139
140
    Returns a TreeDelta with details of added, modified, renamed, and
141
    deleted entries.
142
143
    The root entry is specifically exempt.
144
145
    This only considers versioned files.
146
147
    want_unchanged
148
        If true, also list files unchanged from one version to
149
        the next.
150
151
    specific_files
152
        If true, only check for changes to specified names or
153
        files within them.
154
    """
155
156
    from osutils import is_inside_any
157
    
158
    old_inv = old_tree.inventory
159
    new_inv = new_tree.inventory
160
    delta = TreeDelta()
161
    mutter('start compare_trees')
162
163
    # TODO: match for specific files can be rather smarter by finding
164
    # the IDs of those files up front and then considering only that.
165
166
    for file_id in old_tree:
167
        if file_id in new_tree:
168
            old_ie = old_inv[file_id]
169
            new_ie = new_inv[file_id]
170
171
            kind = old_ie.kind
172
            assert kind == new_ie.kind
173
            
174
            assert kind in ('file', 'directory', 'symlink', 'root_directory'), \
175
                   'invalid file kind %r' % kind
176
177
            if kind == 'root_directory':
178
                continue
179
            
180
            if specific_files:
181
                if (not is_inside_any(specific_files, old_inv.id2path(file_id)) 
182
                    and not is_inside_any(specific_files, new_inv.id2path(file_id))):
183
                    continue
184
185
            if kind == 'file':
186
                old_sha1 = old_tree.get_file_sha1(file_id)
187
                new_sha1 = new_tree.get_file_sha1(file_id)
188
                text_modified = (old_sha1 != new_sha1)
1398 by Robert Collins
integrate in Gustavos x-bit patch
189
                old_exec = old_tree.is_executable(file_id)
190
                new_exec = new_tree.is_executable(file_id)
191
                meta_modified = (old_exec != new_exec)
1092.2.6 by Robert Collins
symlink support updated to work
192
            elif kind == 'symlink':
193
                t1 = old_tree.get_symlink_target(file_id)
194
                t2 = new_tree.get_symlink_target(file_id)
195
                if t1 != t2:
196
                    mutter("    symlink target changed")
1398 by Robert Collins
integrate in Gustavos x-bit patch
197
                    # FIXME: which should we use ?
1092.2.6 by Robert Collins
symlink support updated to work
198
                    text_modified = True
1398 by Robert Collins
integrate in Gustavos x-bit patch
199
                    meta_modified = False
1092.2.6 by Robert Collins
symlink support updated to work
200
                else:
201
                    text_modified = False
1398 by Robert Collins
integrate in Gustavos x-bit patch
202
                    meta_modified = False
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
203
            else:
204
                ## mutter("no text to check for %r %r" % (file_id, kind))
205
                text_modified = False
1398 by Robert Collins
integrate in Gustavos x-bit patch
206
                meta_modified = False
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
207
208
            # TODO: Can possibly avoid calculating path strings if the
209
            # two files are unchanged and their names and parents are
210
            # the same and the parents are unchanged all the way up.
211
            # May not be worthwhile.
212
            
213
            if (old_ie.name != new_ie.name
214
                or old_ie.parent_id != new_ie.parent_id):
215
                delta.renamed.append((old_inv.id2path(file_id),
216
                                      new_inv.id2path(file_id),
217
                                      file_id, kind,
1398 by Robert Collins
integrate in Gustavos x-bit patch
218
                                      text_modified, meta_modified))
219
            elif text_modified or meta_modified:
220
                delta.modified.append((new_inv.id2path(file_id), file_id, kind,
221
                                       text_modified, meta_modified))
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
222
            elif want_unchanged:
223
                delta.unchanged.append((new_inv.id2path(file_id), file_id, kind))
224
        else:
225
            kind = old_inv.get_file_kind(file_id)
226
            if kind == 'root_directory':
227
                continue
228
            old_path = old_inv.id2path(file_id)
229
            if specific_files:
230
                if not is_inside_any(specific_files, old_path):
231
                    continue
232
            delta.removed.append((old_path, file_id, kind))
233
234
    mutter('start looking for new files')
235
    for file_id in new_inv:
236
        if file_id in old_inv:
237
            continue
238
        kind = new_inv.get_file_kind(file_id)
239
        if kind == 'root_directory':
240
            continue
241
        new_path = new_inv.id2path(file_id)
242
        if specific_files:
243
            if not is_inside_any(specific_files, new_path):
244
                continue
245
        delta.added.append((new_path, file_id, kind))
246
            
247
    delta.removed.sort()
248
    delta.added.sort()
249
    delta.renamed.sort()
250
    delta.modified.sort()
251
    delta.unchanged.sort()
252
253
    return delta