1#! /usr/bin/env python3 2 3# Module ndiff version 1.7.0 4# Released to the public domain 08-Dec-2000, 5# by Tim Peters (tim.one@home.com). 6 7# Provided as-is; use at your own risk; no warranty; no promises; enjoy! 8 9# ndiff.py is now simply a front-end to the difflib.ndiff() function. 10# Originally, it contained the difflib.SequenceMatcher class as well. 11# This completes the raiding of reusable code from this formerly 12# self-contained script. 13 14"""ndiff [-q] file1 file2 15 or 16ndiff (-r1 | -r2) < ndiff_output > file1_or_file2 17 18Print a human-friendly file difference report to stdout. Both inter- 19and intra-line differences are noted. In the second form, recreate file1 20(-r1) or file2 (-r2) on stdout, from an ndiff report on stdin. 21 22In the first form, if -q ("quiet") is not specified, the first two lines 23of output are 24 25-: file1 26+: file2 27 28Each remaining line begins with a two-letter code: 29 30 "- " line unique to file1 31 "+ " line unique to file2 32 " " line common to both files 33 "? " line not present in either input file 34 35Lines beginning with "? " attempt to guide the eye to intraline 36differences, and were not present in either input file. These lines can be 37confusing if the source files contain tab characters. 38 39The first file can be recovered by retaining only lines that begin with 40" " or "- ", and deleting those 2-character prefixes; use ndiff with -r1. 41 42The second file can be recovered similarly, but by retaining only " " and 43"+ " lines; use ndiff with -r2; or, on Unix, the second file can be 44recovered by piping the output through 45 46 sed -n '/^[+ ] /s/^..//p' 47""" 48 49__version__ = 1, 7, 0 50 51import difflib, sys 52 53def fail(msg): 54 out = sys.stderr.write 55 out(msg + "\n\n") 56 out(__doc__) 57 return 0 58 59# open a file & return the file object; gripe and return 0 if it 60# couldn't be opened 61def fopen(fname): 62 try: 63 return open(fname) 64 except IOError as detail: 65 return fail("couldn't open " + fname + ": " + str(detail)) 66 67# open two files & spray the diff to stdout; return false iff a problem 68def fcompare(f1name, f2name): 69 f1 = fopen(f1name) 70 f2 = fopen(f2name) 71 if not f1 or not f2: 72 return 0 73 74 a = f1.readlines(); f1.close() 75 b = f2.readlines(); f2.close() 76 for line in difflib.ndiff(a, b): 77 print(line, end=' ') 78 79 return 1 80 81# crack args (sys.argv[1:] is normal) & compare; 82# return false iff a problem 83 84def main(args): 85 import getopt 86 try: 87 opts, args = getopt.getopt(args, "qr:") 88 except getopt.error as detail: 89 return fail(str(detail)) 90 noisy = 1 91 qseen = rseen = 0 92 for opt, val in opts: 93 if opt == "-q": 94 qseen = 1 95 noisy = 0 96 elif opt == "-r": 97 rseen = 1 98 whichfile = val 99 if qseen and rseen: 100 return fail("can't specify both -q and -r") 101 if rseen: 102 if args: 103 return fail("no args allowed with -r option") 104 if whichfile in ("1", "2"): 105 restore(whichfile) 106 return 1 107 return fail("-r value must be 1 or 2") 108 if len(args) != 2: 109 return fail("need 2 filename args") 110 f1name, f2name = args 111 if noisy: 112 print('-:', f1name) 113 print('+:', f2name) 114 return fcompare(f1name, f2name) 115 116# read ndiff output from stdin, and print file1 (which=='1') or 117# file2 (which=='2') to stdout 118 119def restore(which): 120 restored = difflib.restore(sys.stdin.readlines(), which) 121 sys.stdout.writelines(restored) 122 123if __name__ == '__main__': 124 args = sys.argv[1:] 125 if "-profile" in args: 126 import profile, pstats 127 args.remove("-profile") 128 statf = "ndiff.pro" 129 profile.run("main(args)", statf) 130 stats = pstats.Stats(statf) 131 stats.strip_dirs().sort_stats('time').print_stats() 132 else: 133 main(args) 134