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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
17
19
from bzrlib import (
21
from bzrlib.inventory import InventoryEntry
22
from bzrlib.trace import mutter
23
from bzrlib.symbol_versioning import deprecated_function
22
from bzrlib.trace import is_quiet
26
25
class TreeDelta(object):
27
26
"""Describes changes from one tree to another.
36
35
(oldpath, newpath, id, kind, text_modified, meta_modified)
37
(path, id, old_kind, new_kind)
38
39
(path, id, kind, text_modified, meta_modified)
44
45
Each id is listed only once.
46
47
Files that are both modified and renamed are listed only in
47
48
renamed, with the text_modified flag true. The text_modified
48
applies either to the the content of the file or the target of the
49
applies either to the content of the file or the target of the
49
50
symbolic link, depending of the kind of file.
51
52
Files are only considered renamed if their name has changed or
104
106
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)
198
110
def get_changes_as_text(self, show_ids=False, show_unchanged=False,
201
113
output = StringIO.StringIO()
202
self.show(output, show_ids, show_unchanged, short_status)
114
report_delta(output, self, short_status, show_ids, show_unchanged)
203
115
return output.getvalue()
291
208
'unchanged': ' ',
295
214
self.versioned_map = {'added': '+', # versioned target
296
215
'unchanged': ' ', # versioned in both
297
216
'removed': '-', # versioned in source
298
217
'unversioned': '?', # versioned in neither
300
219
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,))
302
233
def report(self, file_id, paths, versioned, renamed, modified, exe_change,
304
235
"""Report one change to a file
306
237
:param file_id: The file_id of the file
307
:param path: The old and new paths as generated by Tree._iter_changes.
238
:param path: The old and new paths as generated by Tree.iter_changes.
308
239
:param versioned: may be 'added', 'removed', 'unchanged', or
310
241
:param renamed: may be True or False
311
242
:param modified: may be 'created', 'deleted', 'kind changed',
312
243
'modified' or 'unchanged'.
313
244
:param exe_change: True if the execute bit has changed
314
:param kind: A pair of file kinds, as generated by Tree._iter_changes.
245
:param kind: A pair of file kinds, as generated by Tree.iter_changes.
315
246
None indicates no file present.
317
250
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,
319
255
if versioned == 'unversioned':
320
256
# skip ignored unversioned files if needed.
321
257
if self.unversioned_filter is not None:
409
346
versioned_change = versioned_change_map[versioned]
410
347
reporter.report(file_id, path, versioned_change, renamed, modified,
411
348
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', ' ')