17
17
from bzrlib.delta import compare_trees
18
18
from bzrlib.errors import BzrError
19
19
import bzrlib.errors as errors
20
from bzrlib.patiencediff import unified_diff
21
import bzrlib.patiencediff
20
22
from bzrlib.symbol_versioning import *
23
from bzrlib.textfile import check_text_lines
21
24
from bzrlib.trace import mutter
23
27
# TODO: Rather than building a changeset object, we should probably
24
28
# invoke callbacks on an object. That object can either accumulate a
25
29
# list, write them out directly, etc etc.
27
def internal_diff(old_filename, oldlines, new_filename, newlines, to_file):
31
def internal_diff(old_filename, oldlines, new_filename, newlines, to_file,
32
allow_binary=False, sequence_matcher=None):
30
33
# FIXME: difflib is wrong if there is no trailing newline.
31
34
# The syntax used by patch seems to be "\ No newline at
32
35
# end of file" following the last diff line from that
42
45
# both sequences are empty.
43
46
if not oldlines and not newlines:
49
if allow_binary is False:
50
check_text_lines(oldlines)
51
check_text_lines(newlines)
46
ud = difflib.unified_diff(oldlines, newlines,
47
fromfile=old_filename+'\t',
48
tofile=new_filename+'\t')
53
if sequence_matcher is None:
54
sequence_matcher = bzrlib.patiencediff.PatienceSequenceMatcher
55
ud = unified_diff(oldlines, newlines,
56
fromfile=old_filename+'\t',
57
tofile=new_filename+'\t',
58
sequencematcher=sequence_matcher)
51
61
# work-around for difflib being too smart for its own good
186
196
def diff_cmd_helper(tree, specific_files, external_diff_options,
187
old_revision_spec=None, new_revision_spec=None):
197
old_revision_spec=None, new_revision_spec=None,
198
old_label='a/', new_label='b/'):
188
199
"""Helper for cmd_diff.
223
234
new_tree = spec_tree(new_revision_spec)
225
236
return show_diff_trees(old_tree, new_tree, sys.stdout, specific_files,
226
external_diff_options)
237
external_diff_options,
238
old_label=old_label, new_label=new_label)
229
241
def show_diff_trees(old_tree, new_tree, to_file, specific_files=None,
230
external_diff_options=None):
242
external_diff_options=None,
243
old_label='a/', new_label='b/'):
231
244
"""Show in text form the changes from one tree to another.
241
254
new_tree.lock_read()
243
256
return _show_diff_trees(old_tree, new_tree, to_file,
244
specific_files, external_diff_options)
257
specific_files, external_diff_options,
258
old_label=old_label, new_label=new_label)
246
260
new_tree.unlock()
251
265
def _show_diff_trees(old_tree, new_tree, to_file,
252
specific_files, external_diff_options):
254
# TODO: Options to control putting on a prefix or suffix, perhaps
255
# as a format string?
266
specific_files, external_diff_options,
267
old_label='a/', new_label='b/' ):
259
269
DEVNULL = '/dev/null'
260
270
# Windows users, don't panic about this filename -- it is a
281
291
for path, file_id, kind in delta.removed:
283
print >>to_file, '=== removed %s %r' % (kind, old_label + path)
293
print >>to_file, '=== removed %s %r' % (kind, path)
284
294
old_tree.inventory[file_id].diff(diff_file, old_label + path, old_tree,
285
295
DEVNULL, None, None, to_file)
286
296
for path, file_id, kind in delta.added:
288
print >>to_file, '=== added %s %r' % (kind, new_label + path)
298
print >>to_file, '=== added %s %r' % (kind, path)
289
299
new_tree.inventory[file_id].diff(diff_file, new_label + path, new_tree,
290
300
DEVNULL, None, None, to_file,
295
305
prop_str = get_prop_change(meta_modified)
296
306
print >>to_file, '=== renamed %s %r => %r%s' % (
297
kind, old_label + old_path, new_label + new_path, prop_str)
307
kind, old_path, new_path, prop_str)
298
308
_maybe_diff_file_or_symlink(old_label, old_path, old_tree, file_id,
299
309
new_label, new_path, new_tree,
300
310
text_modified, kind, to_file, diff_file)
301
311
for path, file_id, kind, text_modified, meta_modified in delta.modified:
303
313
prop_str = get_prop_change(meta_modified)
304
print >>to_file, '=== modified %s %r%s' % (kind, old_label + path,
314
print >>to_file, '=== modified %s %r%s' % (kind, path, prop_str)
306
315
if text_modified:
307
316
_maybe_diff_file_or_symlink(old_label, path, old_tree, file_id,
308
317
new_label, path, new_tree,
322
331
raise errors.PathsNotVersionedError(sorted(unversioned))
334
def _raise_if_nonexistent(paths, old_tree, new_tree):
335
"""Complain if paths are not in either inventory or tree.
337
It's OK with the files exist in either tree's inventory, or
338
if they exist in the tree but are not versioned.
340
This can be used by operations such as bzr status that can accept
341
unknown or ignored files.
343
mutter("check paths: %r", paths)
346
s = old_tree.filter_unversioned_files(paths)
347
s = new_tree.filter_unversioned_files(s)
348
s = [path for path in s if not new_tree.has_filename(path)]
350
raise errors.PathsDoNotExist(sorted(s))
325
353
def get_prop_change(meta_modified):
326
354
if meta_modified:
327
355
return " (properties changed)"