3 # scons-diff.py - diff-like utility for comparing SCons trees
5 # This supports most common diff options (with some quirks, like you can't
6 # just say -c and have it use a default value), but canonicalizes the
7 # various version strings within the file like __revision__, __build__,
8 # etc. so that you can diff trees without having to ignore changes in
18 Usage: scons-diff.py [OPTIONS] dir1 dir2
20 -c NUM, --context=NUM Print NUM lines of copied context.
21 -h, --help Print this message and exit.
22 -n Don't canonicalize SCons lines.
23 -q, --quiet Print only whether files differ.
24 -r, --recursive Recursively compare found subdirectories.
25 -s Report when two files are the same.
26 -u NUM, --unified=NUM Print NUM lines of unified context.
29 opts
, args
= getopt
.getopt(sys
.argv
[1:],
31 ['context=', 'help', 'recursive', 'unified='])
40 def diff_line(left
, right
):
42 opts
= ' ' + ' '.join(diff_options
)
45 print('diff%s %s %s' % (opts
, left
, right
))
51 diff_options
.append(o
)
52 elif o
in ('-h', '--help'):
56 diff_options
.append(o
)
60 diff_line
= lambda l
, r
: None
61 elif o
in ('-r', '--recursive'):
63 diff_options
.append(o
)
70 sys
.stderr
.write(Usage
)
73 def quiet_diff(a
, b
, fromfile
='', tofile
='',
74 fromfiledate
='', tofiledate
='', n
=3, lineterm
='\n'):
76 A function with the same calling signature as difflib.context_diff
77 (diff -c) and difflib.unified_diff (diff -u) but which prints
78 output like the simple, unadorned 'diff" command.
83 return ['Files %s and %s differ\n' % (fromfile
, tofile
)]
85 def simple_diff(a
, b
, fromfile
='', tofile
='',
86 fromfiledate
='', tofiledate
='', n
=3, lineterm
='\n'):
88 A function with the same calling signature as difflib.context_diff
89 (diff -c) and difflib.unified_diff (diff -u) but which prints
90 output like the simple, unadorned 'diff" command.
92 sm
= difflib
.SequenceMatcher(None, a
, b
)
94 return x1
+1 == x2
and str(x2
) or '%s,%s' % (x1
+1, x2
)
96 for op
, a1
, a2
, b1
, b2
in sm
.get_opcodes():
98 result
.append("%sd%d\n" % (comma(a1
, a2
), b1
))
99 result
.extend(['< ' + l
for l
in a
[a1
:a2
]])
101 result
.append("%da%s\n" % (a1
, comma(b1
, b2
)))
102 result
.extend(['> ' + l
for l
in b
[b1
:b2
]])
103 elif op
== 'replace':
104 result
.append("%sc%s\n" % (comma(a1
, a2
), comma(b1
, b2
)))
105 result
.extend(['< ' + l
for l
in a
[a1
:a2
]])
106 result
.append('---\n')
107 result
.extend(['> ' + l
for l
in b
[b1
:b2
]])
111 '-c' : difflib
.context_diff
,
113 '-u' : difflib
.unified_diff
,
116 diff_function
= diff_map
.get(diff_type
, simple_diff
)
118 baseline_re
= re
.compile(r
'(# |@REM )/home/\S+/baseline/')
119 comment_rev_re
= re
.compile(r
'(# |@REM )(\S+) 0.96.[CD]\d+ \S+ \S+( knight)')
120 revision_re
= re
.compile(r
'__revision__ = "[^"]*"')
121 build_re
= re
.compile(r
'__build__ = "[^"]*"')
122 date_re
= re
.compile(r
'__date__ = "[^"]*"')
124 def lines_read(file):
125 return open(file).readlines()
127 def lines_massage(file):
128 text
= open(file).read()
129 text
= baseline_re
.sub('\\1', text
)
130 text
= comment_rev_re
.sub('\\1\\2\\3', text
)
131 text
= revision_re
.sub('__revision__ = "__FILE__"', text
)
132 text
= build_re
.sub('__build__ = "0.96.92.DXXX"', text
)
133 text
= date_re
.sub('__date__ = "2006/08/25 02:59:00"', text
)
134 return text
.splitlines(1)
140 lines_function
= lines_map
.get(edit_type
, lines_massage
)
142 def do_diff(left
, right
, diff_subdirs
):
143 if os
.path
.isfile(left
) and os
.path
.isfile(right
):
144 diff_file(left
, right
)
145 elif not os
.path
.isdir(left
):
146 diff_file(left
, os
.path
.join(right
, os
.path
.split(left
)[1]))
147 elif not os
.path
.isdir(right
):
148 diff_file(os
.path
.join(left
, os
.path
.split(right
)[1]), right
)
150 diff_dir(left
, right
)
152 def diff_file(left
, right
):
153 l
= lines_function(left
)
154 r
= lines_function(right
)
155 d
= diff_function(l
, r
, left
, right
, context
)
159 sys
.stderr
.write('IndexError diffing %s and %s\n' % (left
, right
))
162 diff_line(left
, right
)
165 print('Files %s and %s are identical' % (left
, right
))
167 def diff_dir(left
, right
):
168 llist
= os
.listdir(left
)
169 rlist
= os
.listdir(right
)
175 for x
in sorted([ x
for x
in list(u
.keys()) if x
[-4:] != '.pyc' ]):
178 do_diff(os
.path
.join(left
, x
),
179 os
.path
.join(right
, x
),
182 print('Only in %s: %s' % (left
, x
))
184 print('Only in %s: %s' % (right
, x
))
186 do_diff(left
, right
, True)
190 # indent-tabs-mode:nil
192 # vim: set expandtab tabstop=4 shiftwidth=4: