385
385
old_tree.unlock()
388
def _show_diff_trees(old_tree, new_tree, to_file,
389
specific_files, external_diff_options, path_encoding,
390
old_label='a/', new_label='b/', extra_trees=None):
392
# GNU Patch uses the epoch date to detect files that are being added
393
# or removed in a diff.
394
EPOCH_DATE = '1970-01-01 00:00:00 +0000'
396
# TODO: Generation of pseudo-diffs for added/deleted files could
397
# be usefully made into a much faster special case.
399
if external_diff_options:
400
assert isinstance(external_diff_options, basestring)
401
opts = external_diff_options.split()
402
def diff_file(olab, olines, nlab, nlines, to_file):
403
external_diff(olab, olines, nlab, nlines, to_file, opts)
405
diff_file = internal_diff
407
delta = new_tree.changes_from(old_tree,
408
specific_files=specific_files,
409
extra_trees=extra_trees, require_versioned=True)
412
differ = Differ(old_tree, new_tree, to_file, diff_file)
413
for path, file_id, kind in delta.removed:
415
path_encoded = path.encode(path_encoding, "replace")
416
to_file.write("=== removed %s '%s'\n" % (kind, path_encoded))
417
old_name = '%s%s\t%s' % (old_label, path,
418
_patch_header_date(old_tree, file_id, path))
419
new_name = '%s%s\t%s' % (new_label, path, EPOCH_DATE)
420
differ.diff(file_id, old_name, new_name)
421
for path, file_id, kind in delta.added:
423
path_encoded = path.encode(path_encoding, "replace")
424
to_file.write("=== added %s '%s'\n" % (kind, path_encoded))
425
old_name = '%s%s\t%s' % (old_label, path, EPOCH_DATE)
426
new_name = '%s%s\t%s' % (new_label, path,
427
_patch_header_date(new_tree, file_id, path))
428
differ.diff(file_id, old_name, new_name)
429
for (old_path, new_path, file_id, kind,
430
text_modified, meta_modified) in delta.renamed:
432
prop_str = get_prop_change(meta_modified)
433
oldpath_encoded = old_path.encode(path_encoding, "replace")
434
newpath_encoded = new_path.encode(path_encoding, "replace")
435
to_file.write("=== renamed %s '%s' => '%s'%s\n" % (kind,
436
oldpath_encoded, newpath_encoded, prop_str))
437
old_name = '%s%s\t%s' % (old_label, old_path,
438
_patch_header_date(old_tree, file_id,
440
new_name = '%s%s\t%s' % (new_label, new_path,
441
_patch_header_date(new_tree, file_id,
443
_maybe_diff_file_or_symlink(old_name, old_tree, file_id,
445
text_modified, differ)
446
for path, file_id, kind, text_modified, meta_modified in delta.modified:
448
prop_str = get_prop_change(meta_modified)
449
path_encoded = path.encode(path_encoding, "replace")
450
to_file.write("=== modified %s '%s'%s\n" % (kind,
451
path_encoded, prop_str))
452
# The file may be in a different location in the old tree (because
453
# the containing dir was renamed, but the file itself was not)
454
old_path = old_tree.id2path(file_id)
455
old_name = '%s%s\t%s' % (old_label, old_path,
456
_patch_header_date(old_tree, file_id, old_path))
457
new_name = '%s%s\t%s' % (new_label, path,
458
_patch_header_date(new_tree, file_id, path))
460
_maybe_diff_file_or_symlink(old_name, old_tree, file_id, new_name,
461
new_tree, True, differ)
466
390
def _patch_header_date(tree, file_id, path):
507
431
class Differ(object):
509
def __init__(self, old_tree, new_tree, to_file, text_diff):
433
def __init__(self, old_tree, new_tree, to_file, text_diff,
434
path_encoding='utf-8'):
510
435
self.old_tree = old_tree
511
436
self.new_tree = new_tree
512
437
self.to_file = to_file
513
438
self.text_diff = text_diff
439
self.path_encoding = path_encoding
442
def from_trees_options(klass, old_tree, new_tree, to_file,
443
external_diff_options, path_encoding):
444
if external_diff_options:
445
assert isinstance(external_diff_options, basestring)
446
opts = external_diff_options.split()
447
def diff_file(olab, olines, nlab, nlines, to_file):
448
external_diff(olab, olines, nlab, nlines, to_file, opts)
450
diff_file = internal_diff
451
return klass(old_tree, new_tree, to_file, diff_file, path_encoding)
453
def show_diff(self, specific_files, old_label='', new_label='',
455
# GNU Patch uses the epoch date to detect files that are being added
456
# or removed in a diff.
457
EPOCH_DATE = '1970-01-01 00:00:00 +0000'
459
# TODO: Generation of pseudo-diffs for added/deleted files could
460
# be usefully made into a much faster special case.
462
delta = self.new_tree.changes_from(self.old_tree,
463
specific_files=specific_files,
464
extra_trees=extra_trees, require_versioned=True)
467
for path, file_id, kind in delta.removed:
469
path_encoded = path.encode(self.path_encoding, "replace")
470
self.to_file.write("=== removed %s '%s'\n" % (kind, path_encoded))
471
old_name = '%s%s\t%s' % (old_label, path,
472
_patch_header_date(self.old_tree, file_id,
474
new_name = '%s%s\t%s' % (new_label, path, EPOCH_DATE)
475
self.diff(file_id, old_name, new_name)
477
for path, file_id, kind in delta.added:
479
path_encoded = path.encode(self.path_encoding, "replace")
480
self.to_file.write("=== added %s '%s'\n" % (kind, path_encoded))
481
old_name = '%s%s\t%s' % (old_label, path, EPOCH_DATE)
482
new_name = '%s%s\t%s' % (new_label, path,
483
_patch_header_date(self.new_tree, file_id,
485
self.diff(file_id, old_name, new_name)
486
for (old_path, new_path, file_id, kind,
487
text_modified, meta_modified) in delta.renamed:
489
prop_str = get_prop_change(meta_modified)
490
oldpath_encoded = old_path.encode(self.path_encoding, "replace")
491
newpath_encoded = new_path.encode(self.path_encoding, "replace")
492
self.to_file.write("=== renamed %s '%s' => '%s'%s\n" % (kind,
493
oldpath_encoded, newpath_encoded, prop_str))
494
old_name = '%s%s\t%s' % (old_label, old_path,
495
_patch_header_date(self.old_tree, file_id,
497
new_name = '%s%s\t%s' % (new_label, new_path,
498
_patch_header_date(self.new_tree, file_id,
500
_maybe_diff_file_or_symlink(old_name, self.old_tree, file_id,
501
new_name, self.new_tree,
503
for path, file_id, kind, text_modified, meta_modified in\
506
prop_str = get_prop_change(meta_modified)
507
path_encoded = path.encode(self.path_encoding, "replace")
508
self.to_file.write("=== modified %s '%s'%s\n" % (kind,
509
path_encoded, prop_str))
510
# The file may be in a different location in the old tree (because
511
# the containing dir was renamed, but the file itself was not)
512
old_path = self.old_tree.id2path(file_id)
513
old_date = _patch_header_date(self.old_tree, file_id, old_path)
514
old_name = '%s%s\t%s' % (old_label, old_path, old_date)
515
new_date = _patch_header_date(self.new_tree, file_id, path)
516
new_name = '%s%s\t%s' % (new_label, path, new_date)
518
_maybe_diff_file_or_symlink(old_name, self.old_tree, file_id,
519
new_name, self.new_tree, True,
515
523
def diff(self, file_id, old_name, new_name):