~bzr-pqm/bzr/bzr.dev

2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
1
# Copyright (C) 2005, 2006 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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
2225.1.1 by Aaron Bentley
Added revert change display, with tests
17
from bzrlib import (
18
    errors,
19
    osutils,
20
    )
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
21
from bzrlib.inventory import InventoryEntry
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
22
from bzrlib.trace import mutter
1904.2.1 by Martin Pool
compare_trees is deprecated in 0.9 not 0.10
23
from bzrlib.symbol_versioning import deprecated_function, zero_nine
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
24
1732.1.29 by John Arbash Meinel
Update documentation and TODO for compare_trees
25
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
26
class TreeDelta(object):
27
    """Describes changes from one tree to another.
28
29
    Contains four lists:
30
31
    added
32
        (path, id, kind)
33
    removed
34
        (path, id, kind)
35
    renamed
1398 by Robert Collins
integrate in Gustavos x-bit patch
36
        (oldpath, newpath, id, kind, text_modified, meta_modified)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
37
    modified
1398 by Robert Collins
integrate in Gustavos x-bit patch
38
        (path, id, kind, text_modified, meta_modified)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
39
    unchanged
40
        (path, id, kind)
41
42
    Each id is listed only once.
43
44
    Files that are both modified and renamed are listed only in
1092.2.6 by Robert Collins
symlink support updated to work
45
    renamed, with the text_modified flag true. The text_modified
46
    applies either to the the content of the file or the target of the
47
    symbolic link, depending of the kind of file.
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
48
49
    Files are only considered renamed if their name has changed or
50
    their parent directory has changed.  Renaming a directory
51
    does not count as renaming all its contents.
52
53
    The lists are normally sorted when the delta is created.
54
    """
55
    def __init__(self):
56
        self.added = []
57
        self.removed = []
58
        self.renamed = []
59
        self.modified = []
60
        self.unchanged = []
61
62
    def __eq__(self, other):
63
        if not isinstance(other, TreeDelta):
64
            return False
65
        return self.added == other.added \
66
               and self.removed == other.removed \
67
               and self.renamed == other.renamed \
68
               and self.modified == other.modified \
69
               and self.unchanged == other.unchanged
70
71
    def __ne__(self, other):
72
        return not (self == other)
73
74
    def __repr__(self):
75
        return "TreeDelta(added=%r, removed=%r, renamed=%r, modified=%r," \
76
            " unchanged=%r)" % (self.added, self.removed, self.renamed,
77
            self.modified, self.unchanged)
78
79
    def has_changed(self):
1189 by Martin Pool
- BROKEN: partial support for commit into weave
80
        return bool(self.modified
81
                    or self.added
82
                    or self.removed
83
                    or self.renamed)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
84
85
    def touches_file_id(self, file_id):
86
        """Return True if file_id is modified by this delta."""
87
        for l in self.added, self.removed, self.modified:
88
            for v in l:
89
                if v[1] == file_id:
90
                    return True
91
        for v in self.renamed:
92
            if v[2] == file_id:
93
                return True
94
        return False
95
            
96
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
97
    def show(self, to_file, show_ids=False, show_unchanged=False, short_status=False):
1780.2.1 by Robert Collins
Remove some unused imports.
98
        """output this delta in status-like form to to_file."""
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
99
        def show_list(files, short_status_letter=''):
1398 by Robert Collins
integrate in Gustavos x-bit patch
100
            for item in files:
101
                path, fid, kind = item[:3]
102
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
103
                if kind == 'directory':
104
                    path += '/'
105
                elif kind == 'symlink':
106
                    path += '@'
1398 by Robert Collins
integrate in Gustavos x-bit patch
107
108
                if len(item) == 5 and item[4]:
109
                    path += '*'
110
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
111
                if show_ids:
2147.2.2 by Keir Mierle
Fix spacing error and add tests for status --short command flag.
112
                    print >>to_file, '%s  %-30s %s' % (short_status_letter, path, fid)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
113
                else:
2147.2.2 by Keir Mierle
Fix spacing error and add tests for status --short command flag.
114
                    print >>to_file, '%s  %s' % (short_status_letter, path)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
115
            
116
        if self.removed:
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
117
            if not short_status:
118
                print >>to_file, 'removed:'
119
                show_list(self.removed)
120
            else:
121
                show_list(self.removed, 'D')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
122
                
123
        if self.added:
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
124
            if not short_status:
125
                print >>to_file, 'added:'
126
                show_list(self.added)
127
            else:
128
                show_list(self.added, 'A')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
129
1185.36.2 by Daniel Silverstone
Allow the delta display routine to show when a file
130
        extra_modified = []
131
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
132
        if self.renamed:
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
133
            short_status_letter = 'R'
134
            if not short_status:
135
                print >>to_file, 'renamed:'
136
                short_status_letter = ''
1398 by Robert Collins
integrate in Gustavos x-bit patch
137
            for (oldpath, newpath, fid, kind,
138
                 text_modified, meta_modified) in self.renamed:
1185.36.2 by Daniel Silverstone
Allow the delta display routine to show when a file
139
                if text_modified or meta_modified:
140
                    extra_modified.append((newpath, fid, kind,
141
                                           text_modified, meta_modified))
1398 by Robert Collins
integrate in Gustavos x-bit patch
142
                if meta_modified:
143
                    newpath += '*'
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
144
                if show_ids:
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
145
                    print >>to_file, '%s  %s => %s %s' % (short_status_letter,
146
                                                          oldpath, newpath, fid)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
147
                else:
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
148
                    print >>to_file, '%s  %s => %s' % (short_status_letter,
149
                                                       oldpath, newpath)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
150
                    
1185.36.2 by Daniel Silverstone
Allow the delta display routine to show when a file
151
        if self.modified or extra_modified:
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
152
            short_status_letter = 'M'
153
            if not short_status:
154
                print >>to_file, 'modified:'
155
                short_status_letter = ''
156
            show_list(self.modified, short_status_letter)
157
            show_list(extra_modified, short_status_letter)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
158
            
159
        if show_unchanged and self.unchanged:
2147.2.1 by Keir Mierle
Add a --short flag to status to get svn-style status
160
            if not short_status:
161
                print >>to_file, 'unchanged:'
162
                show_list(self.unchanged)
163
            else:
164
                show_list(self.unchanged, 'S')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
165
166
1904.2.1 by Martin Pool
compare_trees is deprecated in 0.9 not 0.10
167
@deprecated_function(zero_nine)
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
168
def compare_trees(old_tree, new_tree, want_unchanged=False,
169
                  specific_files=None, extra_trees=None,
1731.1.62 by Aaron Bentley
Changes from review comments
170
                  require_versioned=False):
1852.11.1 by Robert Collins
Deprecate compare_trees and move its body to InterTree.changes_from.
171
    """compare_trees was deprecated in 0.10. Please see Tree.changes_from."""
172
    return new_tree.changes_from(old_tree,
173
        want_unchanged=want_unchanged,
174
        specific_files=specific_files,
175
        extra_trees=extra_trees,
1731.1.33 by Aaron Bentley
Revert no-special-root changes
176
        require_versioned=require_versioned,
1731.1.62 by Aaron Bentley
Changes from review comments
177
        include_root=False)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
178
179
180
def _compare_trees(old_tree, new_tree, want_unchanged, specific_file_ids,
181
                   include_root):
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
182
    delta = TreeDelta()
1908.3.1 by Carl Friedrich Bolz
Clean up some mutter() calls.
183
    # mutter('start compare_trees')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
184
2012.1.2 by Aaron Bentley
reimplement compare_trees
185
    for (file_id, path, content_change, versioned, parent_id, name, kind,
2012.1.10 by Aaron Bentley
Make iter_changes private, so it can be changed freely
186
         executable) in new_tree._iter_changes(old_tree, want_unchanged, 
187
                                               specific_file_ids):
2012.1.8 by Aaron Bentley
Merge from bzr.dev
188
        if not include_root and (None, None) == parent_id:
2012.1.2 by Aaron Bentley
reimplement compare_trees
189
            continue
2012.1.3 by Aaron Bentley
Always generate tuples (because kind is always used, even when not different)
190
        assert kind[0] == kind[1] or None in kind
2012.1.2 by Aaron Bentley
reimplement compare_trees
191
        # the only 'kind change' permitted is creation/deletion
2012.1.4 by Aaron Bentley
Simplify add/remove code
192
        fully_present = tuple((versioned[x] and kind[x] is not None) for
193
                              x in range(2))
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
194
        if fully_present[0] != fully_present[1]:
195
            if fully_present[1] is True:
196
                delta.added.append((path, file_id, kind[1]))
197
            else:
198
                assert fully_present[0] is True
199
                old_path = old_tree.id2path(file_id)
200
                delta.removed.append((old_path, file_id, kind[0]))
201
        elif fully_present[0] is False:
202
            continue
2012.1.3 by Aaron Bentley
Always generate tuples (because kind is always used, even when not different)
203
        elif name[0] != name[1] or parent_id[0] != parent_id[1]:
2012.1.4 by Aaron Bentley
Simplify add/remove code
204
            # If the name changes, or the parent_id changes, we have a rename
205
            # (if we move a parent, that doesn't count as a rename for the
206
            # file)
2012.1.2 by Aaron Bentley
reimplement compare_trees
207
            old_path = old_tree.id2path(file_id)
1732.1.7 by John Arbash Meinel
Instead of iterating randomly in both trees, _compare_trees now iterates in order on both trees simultaneously.
208
            delta.renamed.append((old_path,
2012.1.2 by Aaron Bentley
reimplement compare_trees
209
                                  path,
210
                                  file_id, 
2012.1.3 by Aaron Bentley
Always generate tuples (because kind is always used, even when not different)
211
                                  kind[1],
212
                                  content_change, 
213
                                  (executable[0] != executable[1])))
214
        elif content_change is True or executable[0] != executable[1]:
215
            delta.modified.append((path, file_id, kind[1],
216
                                   content_change, 
217
                                   (executable[0] != executable[1])))
2012.1.2 by Aaron Bentley
reimplement compare_trees
218
        else:
2012.1.3 by Aaron Bentley
Always generate tuples (because kind is always used, even when not different)
219
            delta.unchanged.append((path, file_id, kind[1]))
1732.1.7 by John Arbash Meinel
Instead of iterating randomly in both trees, _compare_trees now iterates in order on both trees simultaneously.
220
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
221
    delta.removed.sort()
222
    delta.added.sort()
223
    delta.renamed.sort()
1732.1.29 by John Arbash Meinel
Update documentation and TODO for compare_trees
224
    # TODO: jam 20060529 These lists shouldn't need to be sorted
225
    #       since we added them in alphabetical order.
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
226
    delta.modified.sort()
227
    delta.unchanged.sort()
228
229
    return delta
2225.1.1 by Aaron Bentley
Added revert change display, with tests
230
231
232
class ChangeReporter(object):
233
    """Report changes between two trees"""
234
235
    def __init__(self, old_inventory, output=None):
236
        self.old_inventory = old_inventory
237
        self.output = output
238
        if self.output is None:
239
            from bzrlib import trace
240
            self.output = trace.note
241
242
    def report(self, file_id, path, versioned, renamed, modified, exe_change,
243
               kind):
244
        """Report one change to a file
2225.1.5 by Aaron Bentley
Clean up whitespace changes
245
2225.1.1 by Aaron Bentley
Added revert change display, with tests
246
        :param file_id: The file_id of the file
247
        :param path: The path the file has (or would have) in the tree (as
248
            generated by Tree._iter_changes)
249
        :param versioned: may be 'added', 'removed', or 'unchanged'
250
        :param renamed: may be True or False
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
251
        :param modified: may be 'created', 'deleted', 'kind changed',
2225.1.1 by Aaron Bentley
Added revert change display, with tests
252
            'modified' or 'unchanged'.
253
        :param exe_change: True if the execute bit has changed
254
        :param kind: A pair of file kinds, as generated by Tree._iter_changes.
255
            None indicates no file present.
256
        """
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
257
        modified_map = {'kind changed': 'K',
258
                        'unchanged': ' ',
2225.1.1 by Aaron Bentley
Added revert change display, with tests
259
                        'created': 'N',
260
                        'modified': 'M',
261
                        'deleted': 'D'}
262
        versioned_map = {'added': '+',
263
                         'unchanged': ' ',
264
                         'removed': '-'}
265
        old_path = ""
266
        if renamed:
267
            old_path = self.old_inventory.id2path(file_id)
268
            rename = "R"
269
        else:
270
            rename = versioned_map[versioned]
271
        if modified == 'kind changed':
272
            if old_path == "":
273
                old_path = path
274
        if modified == 'deleted':
275
            path += osutils.kind_marker(kind[0])
276
        else:
277
            path += osutils.kind_marker(kind[1])
278
        if old_path != "":
279
            old_path += "%s => " % osutils.kind_marker(kind[0])
280
        if exe_change:
281
            exe = '*'
282
        else:
283
            exe = ' '
284
        self.output("%s%s%s %s%s", rename, modified_map[modified], exe,
285
                    old_path, path)
286
287
288
def report_changes(change_iterator, reporter):
289
    """Report the changes from a change iterator.
290
291
    This is essentially a translation from low-level to medium-level changes.
292
    Further processing may be required to produce a human-readable output.
293
    Unfortunately, some tree-changing operations are very complex
294
    :change_iterator: an iterator or sequence of changes in the format
295
        generated by Tree._iter_changes
296
    :param reporter: The ChangeReporter that will report the changes.
297
    """
298
    for (file_id, path, content_change, versioned, parent_id, name, kind,
299
         executable) in change_iterator:
300
        exe_change = False
301
        # files are "renamed" if they are moved or if name changes, as long
302
        # as it had a value
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
303
        if None not in name and (name[0] != name[1] or
2225.1.1 by Aaron Bentley
Added revert change display, with tests
304
                                 parent_id[0] != parent_id[1]):
305
            renamed = True
306
        else:
307
            renamed = False
308
        if kind[0] != kind[1]:
309
            if kind[0] is None:
310
                modified = "created"
311
            elif kind[1] is None:
312
                modified = "deleted"
313
            else:
314
                modified = "kind changed"
315
        else:
316
            if content_change:
317
                modified = "modified"
318
            else:
319
                modified = "unchanged"
320
            if kind[1] == "file":
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
321
                exe_change = (executable[0] != executable[1])
2225.1.1 by Aaron Bentley
Added revert change display, with tests
322
        if versioned[0] != versioned[1]:
323
            if versioned[0]:
324
                versioned_change = "removed"
325
            else:
326
                versioned_change = "added"
327
        else:
328
            versioned_change = "unchanged"
2225.1.2 by Aaron Bentley
Ensure that changes are detected correctly
329
        reporter.report(file_id, path, versioned_change, renamed, modified,
2225.1.1 by Aaron Bentley
Added revert change display, with tests
330
                        exe_change, kind)