62
68
self.unchanged = []
63
69
self.unversioned = []
65
72
def __eq__(self, other):
66
73
if not isinstance(other, TreeDelta):
68
75
return self.added == other.added \
69
and self.removed == other.removed \
70
and self.renamed == other.renamed \
71
and self.modified == other.modified \
72
and self.unchanged == other.unchanged \
73
and self.kind_changed == other.kind_changed \
74
and self.unversioned == other.unversioned
76
and self.removed == other.removed \
77
and self.renamed == other.renamed \
78
and self.modified == other.modified \
79
and self.unchanged == other.unchanged \
80
and self.kind_changed == other.kind_changed \
81
and self.unversioned == other.unversioned
76
83
def __ne__(self, other):
77
84
return not (self == other)
80
87
return "TreeDelta(added=%r, removed=%r, renamed=%r," \
81
88
" kind_changed=%r, modified=%r, unchanged=%r," \
82
89
" unversioned=%r)" % (self.added,
83
self.removed, self.renamed, self.kind_changed, self.modified,
84
self.unchanged, self.unversioned)
90
self.removed, self.renamed, self.kind_changed, self.modified,
91
self.unchanged, self.unversioned)
86
93
def has_changed(self):
87
94
return bool(self.modified
119
125
delta = TreeDelta()
120
126
# mutter('start compare_trees')
122
for (file_id, path, content_change, versioned, parent_id, name, kind,
123
executable) in new_tree.iter_changes(old_tree, want_unchanged,
124
specific_files, extra_trees=extra_trees,
128
for change in new_tree.iter_changes(
129
old_tree, want_unchanged, specific_files, extra_trees=extra_trees,
125
130
require_versioned=require_versioned,
126
131
want_unversioned=want_unversioned):
127
if versioned == (False, False):
128
delta.unversioned.append((path[1], None, kind[1]))
130
if not include_root and (None, None) == parent_id:
132
fully_present = tuple((versioned[x] and kind[x] is not None) for
132
if change.versioned == (False, False):
133
delta.unversioned.append((change.path[1], None, change.kind[1]))
135
if not include_root and (None, None) == change.parent_id:
137
fully_present = tuple(
138
(change.versioned[x] and change.kind[x] is not None)
134
140
if fully_present[0] != fully_present[1]:
135
141
if fully_present[1] is True:
136
delta.added.append((path[1], file_id, kind[1]))
142
delta.added.append((change.path[1], change.file_id, change.kind[1]))
138
delta.removed.append((path[0], file_id, kind[0]))
144
if change.kind[0] == 'symlink' and not new_tree.supports_symlinks():
146
'Ignoring "%s" as symlinks '
147
'are not supported on this filesystem.' % (change.path[0],))
149
delta.removed.append(
150
(change.path[0], change.file_id, change.kind[0]))
139
151
elif fully_present[0] is False:
141
elif name[0] != name[1] or parent_id[0] != parent_id[1]:
152
delta.missing.append((change.path[1], change.file_id, change.kind[1]))
153
elif change.name[0] != change.name[1] or change.parent_id[0] != change.parent_id[1]:
142
154
# If the name changes, or the parent_id changes, we have a rename
143
155
# (if we move a parent, that doesn't count as a rename for the
145
delta.renamed.append((path[0],
150
(executable[0] != executable[1])))
151
elif kind[0] != kind[1]:
152
delta.kind_changed.append((path[1], file_id, kind[0], kind[1]))
153
elif content_change or executable[0] != executable[1]:
154
delta.modified.append((path[1], file_id, kind[1],
156
(executable[0] != executable[1])))
157
delta.renamed.append(
158
(change.path[0], change.path[1], change.file_id,
159
change.kind[1], change.changed_content,
160
(change.executable[0] != change.executable[1])))
161
elif change.kind[0] != change.kind[1]:
162
delta.kind_changed.append(
163
(change.path[1], change.file_id, change.kind[0], change.kind[1]))
164
elif change.changed_content or change.executable[0] != change.executable[1]:
165
delta.modified.append((change.path[1], change.file_id, change.kind[1],
166
change.changed_content,
167
(change.executable[0] != change.executable[1])))
158
delta.unchanged.append((path[1], file_id, kind[1]))
169
delta.unchanged.append((change.path[1], change.file_id, change.kind[1]))
160
171
delta.removed.sort()
161
172
delta.added.sort()
162
173
delta.renamed.sort()
175
def missing_key(change):
176
return (change[0] or '', change[1])
177
delta.missing.sort(key=missing_key)
163
178
# TODO: jam 20060529 These lists shouldn't need to be sorted
164
179
# since we added them in alphabetical order.
165
180
delta.modified.sort()
166
181
delta.unchanged.sort()
182
delta.unversioned.sort()
187
204
:param view_info: A tuple of view_name,view_files if only
188
205
items inside a view are to be reported on, or None for
189
206
no view filtering.
207
:param classify: Add special symbols to indicate file kind.
191
209
if output_file is not None:
192
210
if output is not None:
193
211
raise BzrError('Cannot specify both output and output_file')
194
213
def output(fmt, *args):
195
214
output_file.write((fmt % args) + '\n')
196
215
self.output = output
197
216
if self.output is None:
198
from bzrlib import trace
199
218
self.output = trace.note
200
219
self.suppress_root_add = suppress_root_add
201
220
self.modified_map = {'kind changed': 'K',
202
221
'unchanged': ' ',
206
self.versioned_map = {'added': '+', # versioned target
207
'unchanged': ' ', # versioned in both
208
'removed': '-', # versioned in source
209
'unversioned': '?', # versioned in neither
227
self.versioned_map = {'added': '+', # versioned target
228
'unchanged': ' ', # versioned in both
229
'removed': '-', # versioned in source
230
'unversioned': '?', # versioned in neither
211
232
self.unversioned_filter = unversioned_filter
234
self.kind_marker = osutils.kind_marker
236
self.kind_marker = lambda kind: ''
212
237
if view_info is None:
213
238
self.view_name = None
214
239
self.view_files = []
300
326
:param reporter: The _ChangeReporter that will report the changes.
302
328
versioned_change_map = {
303
(True, True) : 'unchanged',
304
(True, False) : 'removed',
305
(False, True) : 'added',
329
(True, True): 'unchanged',
330
(True, False): 'removed',
331
(False, True): 'added',
306
332
(False, False): 'unversioned',
335
def path_key(change):
336
if change[1][0] is not None:
340
return osutils.splitpath(path)
308
341
for (file_id, path, content_change, versioned, parent_id, name, kind,
309
executable) in change_iterator:
342
executable) in sorted(change_iterator, key=path_key):
310
343
exe_change = False
311
344
# files are "renamed" if they are moved or if name changes, as long
312
345
# as it had a value
313
346
if None not in name and None not in parent_id and\
314
(name[0] != name[1] or parent_id[0] != parent_id[1]):
347
(name[0] != name[1] or parent_id[0] != parent_id[1]):
333
368
reporter.report(file_id, path, versioned_change, renamed, modified,
334
369
exe_change, kind)
336
def report_delta(to_file, delta, short_status=False, show_ids=False,
337
show_unchanged=False, indent='', filter=None):
372
def report_delta(to_file, delta, short_status=False, show_ids=False,
373
show_unchanged=False, indent='', predicate=None, classify=True):
338
374
"""Output this delta in status-like form to to_file.
340
376
:param to_file: A file-like object where the output is displayed.
407
447
meta_modified = item[4]
409
449
to_file.write(prefix)
410
show_path(path, file_id, kind, meta_modified,
450
show_path(path, kind, meta_modified,
411
451
default_format, with_file_id_format)
412
452
if show_more is not None:
415
to_file.write(' %s' % file_id)
455
to_file.write(' %s' % file_id.decode('utf-8'))
416
456
to_file.write('\n')
418
458
show_list(delta.removed, 'removed', 'D')
419
459
show_list(delta.added, 'added', 'A')
460
show_list(delta.missing, 'missing', '!')
420
461
extra_modified = []
421
462
# Reorder delta.renamed tuples so that all lists share the same
422
463
# order for their 3 first fields and that they also begin like
423
464
# the delta.modified tuples
424
465
renamed = [(p, i, k, tm, mm, np)
425
for p, np, i, k, tm, mm in delta.renamed]
466
for p, np, i, k, tm, mm in delta.renamed]
426
467
show_list(renamed, 'renamed', 'R', with_file_id_format='%s',
427
468
show_more=show_more_renamed)
428
469
show_list(delta.kind_changed, 'kind changed', 'K',