13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
17
from bzrlib import (
22
from bzrlib.trace import is_quiet
21
from bzrlib.inventory import InventoryEntry
22
from bzrlib.trace import mutter
23
from bzrlib.symbol_versioning import deprecated_function
25
26
class TreeDelta(object):
26
27
"""Describes changes from one tree to another.
35
36
(oldpath, newpath, id, kind, text_modified, meta_modified)
37
(path, id, old_kind, new_kind)
39
38
(path, id, kind, text_modified, meta_modified)
45
44
Each id is listed only once.
47
46
Files that are both modified and renamed are listed only in
48
47
renamed, with the text_modified flag true. The text_modified
49
applies either to the content of the file or the target of the
48
applies either to the the content of the file or the target of the
50
49
symbolic link, depending of the kind of file.
52
51
Files are only considered renamed if their name has changed or
106
104
if v[1] == file_id:
109
def show(self, to_file, show_ids=False, show_unchanged=False,
110
short_status=False, indent=''):
111
"""output this delta in status-like form to to_file."""
112
def show_list(files, short_status_letter=''):
114
path, fid, kind = item[:3]
116
if kind == 'directory':
118
elif kind == 'symlink':
121
if len(item) == 5 and item[4]:
125
to_file.write(indent + '%s %-30s %s\n' % (short_status_letter,
128
to_file.write(indent + '%s %s\n' % (short_status_letter, path))
132
to_file.write(indent + 'removed:\n')
133
show_list(self.removed)
135
show_list(self.removed, 'D')
139
to_file.write(indent + 'added:\n')
140
show_list(self.added)
142
show_list(self.added, 'A')
147
short_status_letter = 'R'
149
to_file.write(indent + 'renamed:\n')
150
short_status_letter = ''
151
for (oldpath, newpath, fid, kind,
152
text_modified, meta_modified) in self.renamed:
153
if text_modified or meta_modified:
154
extra_modified.append((newpath, fid, kind,
155
text_modified, meta_modified))
159
to_file.write(indent + '%s %s => %s %s\n' % (
160
short_status_letter, oldpath, newpath, fid))
162
to_file.write(indent + '%s %s => %s\n' % (
163
short_status_letter, oldpath, newpath))
165
if self.kind_changed:
167
short_status_letter = 'K'
169
to_file.write(indent + 'kind changed:\n')
170
short_status_letter = ''
171
for (path, fid, old_kind, new_kind) in self.kind_changed:
176
to_file.write(indent + '%s %s (%s => %s)%s\n' % (
177
short_status_letter, path, old_kind, new_kind, suffix))
179
if self.modified or extra_modified:
180
short_status_letter = 'M'
182
to_file.write(indent + 'modified:\n')
183
short_status_letter = ''
184
show_list(self.modified, short_status_letter)
185
show_list(extra_modified, short_status_letter)
187
if show_unchanged and self.unchanged:
189
to_file.write(indent + 'unchanged:\n')
190
show_list(self.unchanged)
192
show_list(self.unchanged, 'S')
195
to_file.write(indent + 'unknown:\n')
196
show_list(self.unversioned)
110
198
def get_changes_as_text(self, show_ids=False, show_unchanged=False,
113
201
output = StringIO.StringIO()
114
report_delta(output, self, short_status, show_ids, show_unchanged)
202
self.show(output, show_ids, show_unchanged, short_status)
115
203
return output.getvalue()
208
291
'unchanged': ' ',
214
295
self.versioned_map = {'added': '+', # versioned target
215
296
'unchanged': ' ', # versioned in both
216
297
'removed': '-', # versioned in source
217
298
'unversioned': '?', # versioned in neither
219
300
self.unversioned_filter = unversioned_filter
221
self.kind_marker = osutils.kind_marker
223
self.kind_marker = lambda kind: ''
224
if view_info is None:
225
self.view_name = None
228
self.view_name = view_info[0]
229
self.view_files = view_info[1]
230
self.output("Operating on whole tree but only reporting on "
231
"'%s' view." % (self.view_name,))
233
302
def report(self, file_id, paths, versioned, renamed, modified, exe_change,
235
304
"""Report one change to a file
237
306
:param file_id: The file_id of the file
238
:param path: The old and new paths as generated by Tree.iter_changes.
307
:param path: The old and new paths as generated by Tree._iter_changes.
239
308
:param versioned: may be 'added', 'removed', 'unchanged', or
241
310
:param renamed: may be True or False
242
311
:param modified: may be 'created', 'deleted', 'kind changed',
243
312
'modified' or 'unchanged'.
244
313
:param exe_change: True if the execute bit has changed
245
:param kind: A pair of file kinds, as generated by Tree.iter_changes.
314
:param kind: A pair of file kinds, as generated by Tree._iter_changes.
246
315
None indicates no file present.
250
317
if paths[1] == '' and versioned == 'added' and self.suppress_root_add:
252
if self.view_files and not osutils.is_inside_any(self.view_files,
255
319
if versioned == 'unversioned':
256
320
# skip ignored unversioned files if needed.
257
321
if self.unversioned_filter is not None:
346
409
versioned_change = versioned_change_map[versioned]
347
410
reporter.report(file_id, path, versioned_change, renamed, modified,
348
411
exe_change, kind)
350
def report_delta(to_file, delta, short_status=False, show_ids=False,
351
show_unchanged=False, indent='', filter=None, classify=True):
352
"""Output this delta in status-like form to to_file.
354
:param to_file: A file-like object where the output is displayed.
356
:param delta: A TreeDelta containing the changes to be displayed
358
:param short_status: Single-line status if True.
360
:param show_ids: Output the file ids if True.
362
:param show_unchanged: Output the unchanged files if True.
364
:param indent: Added at the beginning of all output lines (for merged
367
:param filter: A callable receiving a path and a file id and
368
returning True if the path should be displayed.
370
:param classify: Add special symbols to indicate file kind.
373
def decorate_path(path, kind, meta_modified=None):
376
if kind == 'directory':
378
elif kind == 'symlink':
384
def show_more_renamed(item):
385
(oldpath, file_id, kind,
386
text_modified, meta_modified, newpath) = item
387
dec_new_path = decorate_path(newpath, kind, meta_modified)
388
to_file.write(' => %s' % dec_new_path)
389
if text_modified or meta_modified:
390
extra_modified.append((newpath, file_id, kind,
391
text_modified, meta_modified))
393
def show_more_kind_changed(item):
394
(path, file_id, old_kind, new_kind) = item
395
to_file.write(' (%s => %s)' % (old_kind, new_kind))
397
def show_path(path, file_id, kind, meta_modified,
398
default_format, with_file_id_format):
399
dec_path = decorate_path(path, kind, meta_modified)
401
to_file.write(with_file_id_format % dec_path)
403
to_file.write(default_format % dec_path)
405
def show_list(files, long_status_name, short_status_letter,
406
default_format='%s', with_file_id_format='%-30s',
411
prefix = short_status_letter
414
prefix = indent + prefix + ' '
417
path, file_id, kind = item[:3]
418
if (filter is not None and not filter(path, file_id)):
420
if not header_shown and not short_status:
421
to_file.write(indent + long_status_name + ':\n')
425
meta_modified = item[4]
427
to_file.write(prefix)
428
show_path(path, file_id, kind, meta_modified,
429
default_format, with_file_id_format)
430
if show_more is not None:
433
to_file.write(' %s' % file_id)
436
show_list(delta.removed, 'removed', 'D')
437
show_list(delta.added, 'added', 'A')
438
show_list(delta.missing, 'missing', '!')
440
# Reorder delta.renamed tuples so that all lists share the same
441
# order for their 3 first fields and that they also begin like
442
# the delta.modified tuples
443
renamed = [(p, i, k, tm, mm, np)
444
for p, np, i, k, tm, mm in delta.renamed]
445
show_list(renamed, 'renamed', 'R', with_file_id_format='%s',
446
show_more=show_more_renamed)
447
show_list(delta.kind_changed, 'kind changed', 'K',
448
with_file_id_format='%s',
449
show_more=show_more_kind_changed)
450
show_list(delta.modified + extra_modified, 'modified', 'M')
452
show_list(delta.unchanged, 'unchanged', 'S')
454
show_list(delta.unversioned, 'unknown', ' ')