/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/delta.py

  • Committer: Joe Julian
  • Date: 2010-01-10 02:25:31 UTC
  • mto: (4634.119.7 2.0)
  • mto: This revision was merged to the branch mainline in revision 4959.
  • Revision ID: joe@julianfamily.org-20100110022531-wqk61rsagz8xsiga
Added MANIFEST.in to allow bdist_rpm to have all the required include files and tools. bdist_rpm will still fail to build correctly on some distributions due to a disttools bug http://bugs.python.org/issue644744

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from io import StringIO
18
 
 
19
 
from breezy import (
 
17
from bzrlib import (
 
18
    errors,
20
19
    osutils,
21
 
    trace,
22
20
    )
23
 
from .tree import TreeChange
 
21
from bzrlib.inventory import InventoryEntry
 
22
from bzrlib.trace import mutter, is_quiet
 
23
from bzrlib.symbol_versioning import deprecated_function
24
24
 
25
25
 
26
26
class TreeDelta(object):
27
27
    """Describes changes from one tree to another.
28
28
 
29
 
    Contains seven lists with TreeChange objects.
 
29
    Contains seven lists:
30
30
 
31
31
    added
 
32
        (path, id, kind)
32
33
    removed
 
34
        (path, id, kind)
33
35
    renamed
34
 
    copied
 
36
        (oldpath, newpath, id, kind, text_modified, meta_modified)
35
37
    kind_changed
 
38
        (path, id, old_kind, new_kind)
36
39
    modified
 
40
        (path, id, kind, text_modified, meta_modified)
37
41
    unchanged
 
42
        (path, id, kind)
38
43
    unversioned
 
44
        (path, None, kind)
39
45
 
40
46
    Each id is listed only once.
41
47
 
42
 
    Files that are both modified and renamed or copied are listed only in
43
 
    renamed or copied, with the text_modified flag true. The text_modified
44
 
    applies either to the content of the file or the target of the
 
48
    Files that are both modified and renamed are listed only in
 
49
    renamed, with the text_modified flag true. The text_modified
 
50
    applies either to the the content of the file or the target of the
45
51
    symbolic link, depending of the kind of file.
46
52
 
47
53
    Files are only considered renamed if their name has changed or
50
56
 
51
57
    The lists are normally sorted when the delta is created.
52
58
    """
53
 
 
54
59
    def __init__(self):
55
60
        self.added = []
56
61
        self.removed = []
57
62
        self.renamed = []
58
 
        self.copied = []
59
63
        self.kind_changed = []
60
64
        self.modified = []
61
65
        self.unchanged = []
62
66
        self.unversioned = []
63
 
        self.missing = []
64
67
 
65
68
    def __eq__(self, other):
66
69
        if not isinstance(other, TreeDelta):
67
70
            return False
68
71
        return self.added == other.added \
69
 
            and self.removed == other.removed \
70
 
            and self.renamed == other.renamed \
71
 
            and self.copied == other.copied \
72
 
            and self.modified == other.modified \
73
 
            and self.unchanged == other.unchanged \
74
 
            and self.kind_changed == other.kind_changed \
75
 
            and self.unversioned == other.unversioned
 
72
               and self.removed == other.removed \
 
73
               and self.renamed == other.renamed \
 
74
               and self.modified == other.modified \
 
75
               and self.unchanged == other.unchanged \
 
76
               and self.kind_changed == other.kind_changed \
 
77
               and self.unversioned == other.unversioned
76
78
 
77
79
    def __ne__(self, other):
78
80
        return not (self == other)
79
81
 
80
82
    def __repr__(self):
81
83
        return "TreeDelta(added=%r, removed=%r, renamed=%r," \
82
 
            " copied=%r, kind_changed=%r, modified=%r, unchanged=%r," \
83
 
            " unversioned=%r)" % (
84
 
                self.added, self.removed, self.renamed, self.copied,
85
 
                self.kind_changed, self.modified, self.unchanged,
86
 
                self.unversioned)
 
84
            " kind_changed=%r, modified=%r, unchanged=%r," \
 
85
            " unversioned=%r)" % (self.added,
 
86
            self.removed, self.renamed, self.kind_changed, self.modified,
 
87
            self.unchanged, self.unversioned)
87
88
 
88
89
    def has_changed(self):
89
90
        return bool(self.modified
90
91
                    or self.added
91
92
                    or self.removed
92
93
                    or self.renamed
93
 
                    or self.copied
94
94
                    or self.kind_changed)
95
95
 
 
96
    def touches_file_id(self, file_id):
 
97
        """Return True if file_id is modified by this delta."""
 
98
        for l in self.added, self.removed, self.modified:
 
99
            for v in l:
 
100
                if v[1] == file_id:
 
101
                    return True
 
102
        for v in self.renamed:
 
103
            if v[2] == file_id:
 
104
                return True
 
105
        for v in self.kind_changed:
 
106
            if v[1] == file_id:
 
107
                return True
 
108
        return False
 
109
 
 
110
 
 
111
    def show(self, to_file, show_ids=False, show_unchanged=False,
 
112
             short_status=False, indent='',
 
113
             filter=None):
 
114
        """Output this delta in status-like form to to_file.
 
115
 
 
116
        :param to_file: A file-like object where the output is displayed.
 
117
 
 
118
        :param show_ids: Output the file ids if True.
 
119
 
 
120
        :param show_unchanged: Output the unchanged files if True.
 
121
 
 
122
        :param short_status: Single-line status if True.
 
123
 
 
124
        :param indent: Added at the beginning of all output lines (for merged
 
125
            revisions).
 
126
 
 
127
        :param filter: A callable receiving a path and a file id and
 
128
            returning True if the path should be displayed.
 
129
        """
 
130
 
 
131
        def decorate_path(path, kind, meta_modified=None):
 
132
            if kind == 'directory':
 
133
                path += '/'
 
134
            elif kind == 'symlink':
 
135
                path += '@'
 
136
            if meta_modified:
 
137
                path += '*'
 
138
            return path
 
139
 
 
140
        def show_more_renamed(item):
 
141
            (oldpath, file_id, kind,
 
142
             text_modified, meta_modified, newpath) = item
 
143
            dec_new_path = decorate_path(newpath, kind, meta_modified)
 
144
            to_file.write(' => %s' % dec_new_path)
 
145
            if text_modified or meta_modified:
 
146
                extra_modified.append((newpath, file_id, kind,
 
147
                                       text_modified, meta_modified))
 
148
 
 
149
        def show_more_kind_changed(item):
 
150
            (path, file_id, old_kind, new_kind) = item
 
151
            to_file.write(' (%s => %s)' % (old_kind, new_kind))
 
152
 
 
153
        def show_path(path, file_id, kind, meta_modified,
 
154
                      default_format, with_file_id_format):
 
155
            dec_path = decorate_path(path, kind, meta_modified)
 
156
            if show_ids:
 
157
                to_file.write(with_file_id_format % dec_path)
 
158
            else:
 
159
                to_file.write(default_format % dec_path)
 
160
 
 
161
        def show_list(files, long_status_name, short_status_letter,
 
162
                      default_format='%s', with_file_id_format='%-30s',
 
163
                      show_more=None):
 
164
            if files:
 
165
                header_shown = False
 
166
                if short_status:
 
167
                    prefix = short_status_letter
 
168
                else:
 
169
                    prefix = ''
 
170
                prefix = indent + prefix + '  '
 
171
 
 
172
                for item in files:
 
173
                    path, file_id, kind = item[:3]
 
174
                    if (filter is not None and not filter(path, file_id)):
 
175
                        continue
 
176
                    if not header_shown and not short_status:
 
177
                        to_file.write(indent + long_status_name + ':\n')
 
178
                        header_shown = True
 
179
                    meta_modified = None
 
180
                    if len(item) == 5:
 
181
                        meta_modified = item[4]
 
182
 
 
183
                    to_file.write(prefix)
 
184
                    show_path(path, file_id, kind, meta_modified,
 
185
                              default_format, with_file_id_format)
 
186
                    if show_more is not None:
 
187
                        show_more(item)
 
188
                    if show_ids:
 
189
                        to_file.write(' %s' % file_id)
 
190
                    to_file.write('\n')
 
191
 
 
192
        show_list(self.removed, 'removed', 'D')#
 
193
        show_list(self.added, 'added', 'A')
 
194
        extra_modified = []
 
195
        # Reorder self.renamed tuples so that all lists share the same
 
196
        # order for their 3 first fields and that they also begin like
 
197
        # the self.modified tuples
 
198
        renamed = [(p, i, k, tm, mm, np)
 
199
                   for  p, np, i, k, tm, mm  in self.renamed]
 
200
        show_list(renamed, 'renamed', 'R', with_file_id_format='%s',
 
201
                  show_more=show_more_renamed)
 
202
        show_list(self.kind_changed, 'kind changed', 'K',
 
203
                  with_file_id_format='%s',
 
204
                  show_more=show_more_kind_changed)
 
205
        show_list(self.modified + extra_modified, 'modified', 'M')
 
206
        if show_unchanged:
 
207
            show_list(self.unchanged, 'unchanged', 'S')
 
208
 
 
209
        show_list(self.unversioned, 'unknown', ' ')
 
210
 
96
211
    def get_changes_as_text(self, show_ids=False, show_unchanged=False,
97
 
                            short_status=False):
98
 
        output = StringIO()
99
 
        report_delta(output, self, short_status, show_ids, show_unchanged)
 
212
             short_status=False):
 
213
        import StringIO
 
214
        output = StringIO.StringIO()
 
215
        self.show(output, show_ids, show_unchanged, short_status)
100
216
        return output.getvalue()
101
217
 
102
218
 
107
223
    delta = TreeDelta()
108
224
    # mutter('start compare_trees')
109
225
 
110
 
    for change in new_tree.iter_changes(
111
 
            old_tree, want_unchanged, specific_files, extra_trees=extra_trees,
 
226
    for (file_id, path, content_change, versioned, parent_id, name, kind,
 
227
         executable) in new_tree.iter_changes(old_tree, want_unchanged,
 
228
            specific_files, extra_trees=extra_trees,
112
229
            require_versioned=require_versioned,
113
230
            want_unversioned=want_unversioned):
114
 
        if change.versioned == (False, False):
115
 
            delta.unversioned.append(change)
116
 
            continue
117
 
        if not include_root and (None, None) == change.parent_id:
118
 
            continue
119
 
        fully_present = tuple(
120
 
            (change.versioned[x] and change.kind[x] is not None)
121
 
            for x in range(2))
 
231
        if versioned == (False, False):
 
232
            delta.unversioned.append((path[1], None, kind[1]))
 
233
            continue
 
234
        if not include_root and (None, None) == parent_id:
 
235
            continue
 
236
        fully_present = tuple((versioned[x] and kind[x] is not None) for
 
237
                              x in range(2))
122
238
        if fully_present[0] != fully_present[1]:
123
239
            if fully_present[1] is True:
124
 
                delta.added.append(change)
 
240
                delta.added.append((path[1], file_id, kind[1]))
125
241
            else:
126
 
                if change.kind[0] == 'symlink' and not new_tree.supports_symlinks():
127
 
                    trace.warning(
128
 
                        'Ignoring "%s" as symlinks '
129
 
                        'are not supported on this filesystem.' % (change.path[0],))
130
 
                else:
131
 
                    delta.removed.append(change)
 
242
                delta.removed.append((path[0], file_id, kind[0]))
132
243
        elif fully_present[0] is False:
133
 
            delta.missing.append(change)
134
 
        elif change.name[0] != change.name[1] or change.parent_id[0] != change.parent_id[1]:
135
 
            # If the name changes, or the parent_id changes, we have a rename or copy
 
244
            continue
 
245
        elif name[0] != name[1] or parent_id[0] != parent_id[1]:
 
246
            # If the name changes, or the parent_id changes, we have a rename
136
247
            # (if we move a parent, that doesn't count as a rename for the
137
248
            # file)
138
 
            if change.copied:
139
 
                delta.copied.append(change)
140
 
            else:
141
 
                delta.renamed.append(change)
142
 
        elif change.kind[0] != change.kind[1]:
143
 
            delta.kind_changed.append(change)
144
 
        elif change.changed_content or change.executable[0] != change.executable[1]:
145
 
            delta.modified.append(change)
146
 
        else:
147
 
            delta.unchanged.append(change)
148
 
 
149
 
    def change_key(change):
150
 
        if change.path[0] is None:
151
 
            path = change.path[1]
152
 
        else:
153
 
            path = change.path[0]
154
 
        return (path, change.file_id)
155
 
 
156
 
    delta.removed.sort(key=change_key)
157
 
    delta.added.sort(key=change_key)
158
 
    delta.renamed.sort(key=change_key)
159
 
    delta.copied.sort(key=change_key)
160
 
    delta.missing.sort(key=change_key)
 
249
            delta.renamed.append((path[0],
 
250
                                  path[1],
 
251
                                  file_id,
 
252
                                  kind[1],
 
253
                                  content_change,
 
254
                                  (executable[0] != executable[1])))
 
255
        elif kind[0] != kind[1]:
 
256
            delta.kind_changed.append((path[1], file_id, kind[0], kind[1]))
 
257
        elif content_change or executable[0] != executable[1]:
 
258
            delta.modified.append((path[1], file_id, kind[1],
 
259
                                   content_change,
 
260
                                   (executable[0] != executable[1])))
 
261
        else:
 
262
            delta.unchanged.append((path[1], file_id, kind[1]))
 
263
 
 
264
    delta.removed.sort()
 
265
    delta.added.sort()
 
266
    delta.renamed.sort()
161
267
    # TODO: jam 20060529 These lists shouldn't need to be sorted
162
268
    #       since we added them in alphabetical order.
163
 
    delta.modified.sort(key=change_key)
164
 
    delta.unchanged.sort(key=change_key)
165
 
    delta.unversioned.sort(key=change_key)
 
269
    delta.modified.sort()
 
270
    delta.unchanged.sort()
166
271
 
167
272
    return delta
168
273
 
171
276
    """Report changes between two trees"""
172
277
 
173
278
    def __init__(self, output=None, suppress_root_add=True,
174
 
                 output_file=None, unversioned_filter=None, view_info=None,
175
 
                 classify=True):
 
279
                 output_file=None, unversioned_filter=None, view_info=None):
176
280
        """Constructor
177
281
 
178
282
        :param output: a function with the signature of trace.note, i.e.
187
291
        :param view_info: A tuple of view_name,view_files if only
188
292
            items inside a view are to be reported on, or None for
189
293
            no view filtering.
190
 
        :param classify: Add special symbols to indicate file kind.
191
294
        """
192
295
        if output_file is not None:
193
296
            if output is not None:
194
297
                raise BzrError('Cannot specify both output and output_file')
195
 
 
196
298
            def output(fmt, *args):
197
299
                output_file.write((fmt % args) + '\n')
198
300
        self.output = output
199
301
        if self.output is None:
200
 
            from . import trace
 
302
            from bzrlib import trace
201
303
            self.output = trace.note
202
304
        self.suppress_root_add = suppress_root_add
203
305
        self.modified_map = {'kind changed': 'K',
204
306
                             'unchanged': ' ',
205
307
                             'created': 'N',
206
308
                             'modified': 'M',
207
 
                             'deleted': 'D',
208
 
                             'missing': '!',
209
 
                             }
210
 
        self.versioned_map = {'added': '+',  # versioned target
211
 
                              'unchanged': ' ',  # versioned in both
212
 
                              'removed': '-',  # versioned in source
213
 
                              'unversioned': '?',  # versioned in neither
 
309
                             'deleted': 'D'}
 
310
        self.versioned_map = {'added': '+', # versioned target
 
311
                              'unchanged': ' ', # versioned in both
 
312
                              'removed': '-', # versioned in source
 
313
                              'unversioned': '?', # versioned in neither
214
314
                              }
215
315
        self.unversioned_filter = unversioned_filter
216
 
        if classify:
217
 
            self.kind_marker = osutils.kind_marker
218
 
        else:
219
 
            self.kind_marker = lambda kind: ''
220
316
        if view_info is None:
221
317
            self.view_name = None
222
318
            self.view_files = []
226
322
            self.output("Operating on whole tree but only reporting on "
227
323
                        "'%s' view." % (self.view_name,))
228
324
 
229
 
    def report(self, paths, versioned, renamed, copied, modified, exe_change,
 
325
    def report(self, file_id, paths, versioned, renamed, modified, exe_change,
230
326
               kind):
231
327
        """Report one change to a file
232
328
 
 
329
        :param file_id: The file_id of the file
233
330
        :param path: The old and new paths as generated by Tree.iter_changes.
234
331
        :param versioned: may be 'added', 'removed', 'unchanged', or
235
332
            'unversioned.
236
333
        :param renamed: may be True or False
237
 
        :param copied: may be True or False
238
334
        :param modified: may be 'created', 'deleted', 'kind changed',
239
335
            'modified' or 'unchanged'.
240
336
        :param exe_change: True if the execute bit has changed
241
337
        :param kind: A pair of file kinds, as generated by Tree.iter_changes.
242
338
            None indicates no file present.
243
339
        """
244
 
        if trace.is_quiet():
 
340
        if is_quiet():
245
341
            return
246
342
        if paths[1] == '' and versioned == 'added' and self.suppress_root_add:
247
343
            return
248
344
        if self.view_files and not osutils.is_inside_any(self.view_files,
249
 
                                                         paths[1]):
 
345
            paths[1]):
250
346
            return
251
347
        if versioned == 'unversioned':
252
348
            # skip ignored unversioned files if needed.
260
356
        # ( the path is different OR
261
357
        #   the kind is different)
262
358
        if (versioned == 'unchanged' and
263
 
                (renamed or copied or modified == 'kind changed')):
264
 
            if renamed or copied:
265
 
                # on a rename or copy, we show old and new
 
359
            (renamed or modified == 'kind changed')):
 
360
            if renamed:
 
361
                # on a rename, we show old and new
266
362
                old_path, path = paths
267
363
            else:
268
 
                # if it's not renamed or copied, we're showing both for kind
269
 
                # changes so only show the new path
 
364
                # if it's not renamed, we're showing both for kind changes
 
365
                # so only show the new path
270
366
                old_path, path = paths[1], paths[1]
271
367
            # if the file is not missing in the source, we show its kind
272
368
            # when we show two paths.
273
369
            if kind[0] is not None:
274
 
                old_path += self.kind_marker(kind[0])
 
370
                old_path += osutils.kind_marker(kind[0])
275
371
            old_path += " => "
276
372
        elif versioned == 'removed':
277
373
            # not present in target
282
378
            path = paths[1]
283
379
        if renamed:
284
380
            rename = "R"
285
 
        elif copied:
286
 
            rename = "C"
287
381
        else:
288
382
            rename = self.versioned_map[versioned]
289
383
        # we show the old kind on the new path when the content is deleted.
290
384
        if modified == 'deleted':
291
 
            path += self.kind_marker(kind[0])
 
385
            path += osutils.kind_marker(kind[0])
292
386
        # otherwise we always show the current kind when there is one
293
387
        elif kind[1] is not None:
294
 
            path += self.kind_marker(kind[1])
 
388
            path += osutils.kind_marker(kind[1])
295
389
        if exe_change:
296
390
            exe = '*'
297
391
        else:
311
405
    :param reporter: The _ChangeReporter that will report the changes.
312
406
    """
313
407
    versioned_change_map = {
314
 
        (True, True): 'unchanged',
315
 
        (True, False): 'removed',
316
 
        (False, True): 'added',
 
408
        (True, True)  : 'unchanged',
 
409
        (True, False) : 'removed',
 
410
        (False, True) : 'added',
317
411
        (False, False): 'unversioned',
318
412
        }
319
 
 
320
 
    def path_key(change):
321
 
        if change.path[0] is not None:
322
 
            path = change.path[0]
323
 
        else:
324
 
            path = change.path[1]
325
 
        return osutils.splitpath(path)
326
 
    for change in sorted(change_iterator, key=path_key):
 
413
    for (file_id, path, content_change, versioned, parent_id, name, kind,
 
414
         executable) in change_iterator:
327
415
        exe_change = False
328
416
        # files are "renamed" if they are moved or if name changes, as long
329
417
        # as it had a value
330
 
        if None not in change.name and None not in change.parent_id and\
331
 
                (change.name[0] != change.name[1] or change.parent_id[0] != change.parent_id[1]):
332
 
            if change.copied:
333
 
                copied = True
334
 
                renamed = False
335
 
            else:
336
 
                renamed = True
337
 
                copied = False
 
418
        if None not in name and None not in parent_id and\
 
419
            (name[0] != name[1] or parent_id[0] != parent_id[1]):
 
420
            renamed = True
338
421
        else:
339
 
            copied = False
340
422
            renamed = False
341
 
        if change.kind[0] != change.kind[1]:
342
 
            if change.kind[0] is None:
 
423
        if kind[0] != kind[1]:
 
424
            if kind[0] is None:
343
425
                modified = "created"
344
 
            elif change.kind[1] is None:
 
426
            elif kind[1] is None:
345
427
                modified = "deleted"
346
428
            else:
347
429
                modified = "kind changed"
348
430
        else:
349
 
            if change.changed_content:
 
431
            if content_change:
350
432
                modified = "modified"
351
 
            elif change.kind[0] is None:
352
 
                modified = "missing"
353
433
            else:
354
434
                modified = "unchanged"
355
 
            if change.kind[1] == "file":
356
 
                exe_change = (change.executable[0] != change.executable[1])
357
 
        versioned_change = versioned_change_map[change.versioned]
358
 
        reporter.report(change.path, versioned_change, renamed, copied, modified,
359
 
                        exe_change, change.kind)
360
 
 
361
 
 
362
 
def report_delta(to_file, delta, short_status=False, show_ids=False,
363
 
                 show_unchanged=False, indent='', predicate=None, classify=True):
364
 
    """Output this delta in status-like form to to_file.
365
 
 
366
 
    :param to_file: A file-like object where the output is displayed.
367
 
 
368
 
    :param delta: A TreeDelta containing the changes to be displayed
369
 
 
370
 
    :param short_status: Single-line status if True.
371
 
 
372
 
    :param show_ids: Output the file ids if True.
373
 
 
374
 
    :param show_unchanged: Output the unchanged files if True.
375
 
 
376
 
    :param indent: Added at the beginning of all output lines (for merged
377
 
        revisions).
378
 
 
379
 
    :param predicate: A callable receiving a path returning True if the path
380
 
        should be displayed.
381
 
 
382
 
    :param classify: Add special symbols to indicate file kind.
383
 
    """
384
 
 
385
 
    def decorate_path(path, kind, meta_modified=None):
386
 
        if not classify:
387
 
            return path
388
 
        if kind == 'directory':
389
 
            path += '/'
390
 
        elif kind == 'symlink':
391
 
            path += '@'
392
 
        if meta_modified:
393
 
            path += '*'
394
 
        return path
395
 
 
396
 
    def show_more_renamed(item):
397
 
        dec_new_path = decorate_path(item.path[1], item.kind[1], item.meta_modified())
398
 
        to_file.write(' => %s' % dec_new_path)
399
 
        if item.changed_content or item.meta_modified():
400
 
            extra_modified.append(TreeChange(
401
 
                item.file_id, (item.path[1], item.path[1]),
402
 
                item.changed_content,
403
 
                item.versioned,
404
 
                (item.parent_id[1], item.parent_id[1]),
405
 
                (item.name[1], item.name[1]),
406
 
                (item.kind[1], item.kind[1]),
407
 
                item.executable))
408
 
 
409
 
    def show_more_kind_changed(item):
410
 
        to_file.write(' (%s => %s)' % (item.kind[0], item.kind[1]))
411
 
 
412
 
    def show_path(path, kind, meta_modified,
413
 
                  default_format, with_file_id_format):
414
 
        dec_path = decorate_path(path, kind, meta_modified)
415
 
        if show_ids:
416
 
            to_file.write(with_file_id_format % dec_path)
417
 
        else:
418
 
            to_file.write(default_format % dec_path)
419
 
 
420
 
    def show_list(files, long_status_name, short_status_letter,
421
 
                  default_format='%s', with_file_id_format='%-30s',
422
 
                  show_more=None):
423
 
        if files:
424
 
            header_shown = False
425
 
            if short_status:
426
 
                prefix = short_status_letter
427
 
            else:
428
 
                prefix = ''
429
 
            prefix = indent + prefix + '  '
430
 
 
431
 
            for item in files:
432
 
                if item.path[0] is None:
433
 
                    path = item.path[1]
434
 
                    kind = item.kind[1]
435
 
                else:
436
 
                    path = item.path[0]
437
 
                    kind = item.kind[0]
438
 
                if predicate is not None and not predicate(path):
439
 
                    continue
440
 
                if not header_shown and not short_status:
441
 
                    to_file.write(indent + long_status_name + ':\n')
442
 
                    header_shown = True
443
 
                to_file.write(prefix)
444
 
                show_path(path, kind, item.meta_modified(),
445
 
                          default_format, with_file_id_format)
446
 
                if show_more is not None:
447
 
                    show_more(item)
448
 
                if show_ids and getattr(item, 'file_id', None):
449
 
                    to_file.write(' %s' % item.file_id.decode('utf-8'))
450
 
                to_file.write('\n')
451
 
 
452
 
    show_list(delta.removed, 'removed', 'D')
453
 
    show_list(delta.added, 'added', 'A')
454
 
    show_list(delta.missing, 'missing', '!')
455
 
    extra_modified = []
456
 
    show_list(delta.renamed, 'renamed', 'R', with_file_id_format='%s',
457
 
              show_more=show_more_renamed)
458
 
    show_list(delta.copied, 'copied', 'C', with_file_id_format='%s',
459
 
              show_more=show_more_renamed)
460
 
    show_list(delta.kind_changed, 'kind changed', 'K',
461
 
              with_file_id_format='%s',
462
 
              show_more=show_more_kind_changed)
463
 
    show_list(delta.modified + extra_modified, 'modified', 'M')
464
 
    if show_unchanged:
465
 
        show_list(delta.unchanged, 'unchanged', 'S')
466
 
 
467
 
    show_list(delta.unversioned, 'unknown', ' ')
 
435
            if kind[1] == "file":
 
436
                exe_change = (executable[0] != executable[1])
 
437
        versioned_change = versioned_change_map[versioned]
 
438
        reporter.report(file_id, path, versioned_change, renamed, modified,
 
439
                        exe_change, kind)