Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 1 | #! /usr/bin/env python |
| 2 | |
Tim Peters | 5e824c3 | 2001-08-12 22:25:01 +0000 | [diff] [blame] | 3 | # Module ndiff version 1.7.0 |
Tim Peters | 2f1aeb9 | 2000-12-09 05:03:22 +0000 | [diff] [blame] | 4 | # Released to the public domain 08-Dec-2000, |
| 5 | # by Tim Peters (tim.one@home.com). |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 6 | |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 7 | # Provided as-is; use at your own risk; no warranty; no promises; enjoy! |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 8 | |
Tim Peters | 5e824c3 | 2001-08-12 22:25:01 +0000 | [diff] [blame] | 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 | |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 14 | """ndiff [-q] file1 file2 |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 15 | or |
| 16 | ndiff (-r1 | -r2) < ndiff_output > file1_or_file2 |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 17 | |
| 18 | Print a human-friendly file difference report to stdout. Both inter- |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 19 | and intra-line differences are noted. In the second form, recreate file1 |
| 20 | (-r1) or file2 (-r2) on stdout, from an ndiff report on stdin. |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 21 | |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 22 | In the first form, if -q ("quiet") is not specified, the first two lines |
| 23 | of output are |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 24 | |
| 25 | -: file1 |
| 26 | +: file2 |
| 27 | |
| 28 | Each 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 | |
| 35 | Lines beginning with "? " attempt to guide the eye to intraline |
Tim Peters | 0d430e2 | 2000-11-01 02:51:27 +0000 | [diff] [blame] | 36 | differences, and were not present in either input file. These lines can be |
| 37 | confusing if the source files contain tab characters. |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 38 | |
| 39 | The first file can be recovered by retaining only lines that begin with |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 40 | " " or "- ", and deleting those 2-character prefixes; use ndiff with -r1. |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 41 | |
Tim Peters | 0d430e2 | 2000-11-01 02:51:27 +0000 | [diff] [blame] | 42 | The 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 |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 44 | recovered by piping the output through |
| 45 | |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 46 | sed -n '/^[+ ] /s/^..//p' |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 47 | """ |
| 48 | |
Tim Peters | 5e824c3 | 2001-08-12 22:25:01 +0000 | [diff] [blame] | 49 | __version__ = 1, 7, 0 |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 50 | |
Tim Peters | 5e824c3 | 2001-08-12 22:25:01 +0000 | [diff] [blame] | 51 | import difflib, sys |
Tim Peters | 0d430e2 | 2000-11-01 02:51:27 +0000 | [diff] [blame] | 52 | |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 53 | def fail(msg): |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 54 | out = sys.stderr.write |
| 55 | out(msg + "\n\n") |
| 56 | out(__doc__) |
| 57 | return 0 |
| 58 | |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 59 | # open a file & return the file object; gripe and return 0 if it |
| 60 | # couldn't be opened |
| 61 | def fopen(fname): |
| 62 | try: |
| 63 | return open(fname, 'r') |
| 64 | except IOError, detail: |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 65 | return fail("couldn't open " + fname + ": " + str(detail)) |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 66 | |
| 67 | # open two files & spray the diff to stdout; return false iff a problem |
| 68 | def 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() |
Tim Peters | 8a9c284 | 2001-09-22 21:30:22 +0000 | [diff] [blame] | 76 | for line in difflib.ndiff(a, b): |
| 77 | print line, |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 78 | |
| 79 | return 1 |
| 80 | |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 81 | # crack args (sys.argv[1:] is normal) & compare; |
| 82 | # return false iff a problem |
| 83 | |
| 84 | def main(args): |
| 85 | import getopt |
| 86 | try: |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 87 | opts, args = getopt.getopt(args, "qr:") |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 88 | except getopt.error, detail: |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 89 | return fail(str(detail)) |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 90 | noisy = 1 |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 91 | qseen = rseen = 0 |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 92 | for opt, val in opts: |
| 93 | if opt == "-q": |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 94 | qseen = 1 |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 95 | noisy = 0 |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 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 "12": |
| 105 | restore(whichfile) |
| 106 | return 1 |
| 107 | return fail("-r value must be 1 or 2") |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 108 | if len(args) != 2: |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 109 | return fail("need 2 filename args") |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 110 | f1name, f2name = args |
| 111 | if noisy: |
| 112 | print '-:', f1name |
| 113 | print '+:', f2name |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 114 | return fcompare(f1name, f2name) |
| 115 | |
Tim Peters | 5e824c3 | 2001-08-12 22:25:01 +0000 | [diff] [blame] | 116 | # read ndiff output from stdin, and print file1 (which=='1') or |
| 117 | # file2 (which=='2') to stdout |
| 118 | |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 119 | def restore(which): |
Tim Peters | 5e824c3 | 2001-08-12 22:25:01 +0000 | [diff] [blame] | 120 | restored = difflib.restore(sys.stdin.readlines(), which) |
Tim Peters | 42b6877 | 2001-09-22 21:59:18 +0000 | [diff] [blame^] | 121 | for line in restored: |
| 122 | print line, |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 123 | |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 124 | if __name__ == '__main__': |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 125 | args = sys.argv[1:] |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 126 | if "-profile" in args: |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 127 | import profile, pstats |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 128 | args.remove("-profile") |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 129 | statf = "ndiff.pro" |
Guido van Rossum | a3433e8 | 1999-03-27 13:34:01 +0000 | [diff] [blame] | 130 | profile.run("main(args)", statf) |
Guido van Rossum | 83b8518 | 1998-05-06 17:43:30 +0000 | [diff] [blame] | 131 | stats = pstats.Stats(statf) |
| 132 | stats.strip_dirs().sort_stats('time').print_stats() |
Guido van Rossum | 02ef28b | 1999-03-28 17:55:32 +0000 | [diff] [blame] | 133 | else: |
| 134 | main(args) |