utility to examine recursive differences
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 25 Oct 2011 08:59:33 +0000 (10:59 +0200)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 25 Oct 2011 08:59:33 +0000 (10:59 +0200)
scripts/diff-rec.py [new file with mode: 0755]

diff --git a/scripts/diff-rec.py b/scripts/diff-rec.py
new file mode 100755 (executable)
index 0000000..089ee5f
--- /dev/null
@@ -0,0 +1,135 @@
+#!/usr/bin/python
+
+import os, os.path
+import subprocess
+import re
+
+from optparse import OptionParser
+
+def report_stderr(stderrdata):
+    if stderrdata: 
+        print "STDERR BEG (%d chars)",len(stderrdata)
+        print stderrdata
+        print "STDERR END (%d chars)",len(stderrdata)
+
+def git_update (dir):
+    os.chdir(dir)
+    print "git pull in %s"%dir
+    prog=subprocess.Popen(["git","pull"],stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    try:
+        (stdoutdata, stderrdata) = prog.communicate()
+    except KeyboardInterrupt:
+        raise Exception, "Interrupted by user"
+    prog.wait()
+    print stdoutdata,
+    report_stderr(stderrdata)
+
+
+excludes=[ "*.git*", "*~" ]
+excludes+= [ "*.pyc", "*.png", "*.pdf", "*.out" , "*.DS_Store", "*.lint" ]
+excludes+= [ "listfiles.sh", "python.*" ]
+def run_diff(options):
+    dir1=options.left_dir
+    dir2=options.right_dir
+    command=["diff","-r",]
+    for exclude in excludes:
+        command += [ "-x", "%s"%exclude]
+    command += [dir1,dir2]
+    prog=subprocess.Popen(command,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    print "diffing -r %s %s"%(dir1,dir2)
+    try:
+        (stdoutdata, stderrdata) = prog.communicate()
+    except KeyboardInterrupt:
+        raise Exception, "Interrupted by user"
+    prog.wait()
+    report_stderr(stderrdata)
+
+    re_only_left =re.compile("^Only in %s[:/]"%dir1)
+    re_only_right=re.compile("^Only in %s[:/]"%dir2)
+    re_binary    =re.compile("^Binary files %s.* and %s.*"%(dir1,dir2))
+    re_start_diff=re.compile("diff -r.*%s/(?P<path>.*) %s/(?P=path)"%(dir1,dir2))
+
+    only_left=[]
+    only_right=[]
+    ignored=[]
+    
+    class Context:
+        def __init__ (self,diffs): 
+            self.current_path=''
+            self.current_diff=[]
+            self.diffs=diffs
+        def close_diff(self):
+            if self.current_path: self.diffs[self.current_path]=self.current_diff
+            elif self.current_diff: print """----------
+WARNING, diff with no path %s
+----------"""%self.current_diff
+            self.current_path=''
+            self.current_diff=[]
+        def set_path (self,path):
+            self.current_path=path
+        def insert_line(self,line):
+            self.current_diff.append(line)
+
+    ### parse
+    diffs={}
+    context=Context(diffs)
+    for line in stdoutdata.split("\n"):
+        m=re_only_left.match(line)
+        if m: 
+            context.close_diff()
+            only_left.append(line)
+            continue
+        m=re_only_right.match(line)
+        if m: 
+            context.close_diff()
+            only_right.append(line)
+            continue
+        m=re_binary.match(line)
+        if m:
+            context.close_diff()
+            ignored.append(line)
+            continue
+        m=re_start_diff.match(line)
+        if m:
+            context.close_diff()
+            context.set_path(m.group('path'))
+            continue
+        context.insert_line(line)
+        
+    ### ignore some entries - maybe not needed if we're smart with diff
+        
+    # print report
+    print "< < < < < %d old files/dirs"%len(only_left)
+    for l in only_left:  print "< < < < < ",l
+    print "> > > > > %d new files/dirs"%len(only_right)
+    for l in only_right: print "> > > > > ",l
+    print "= = = = = %d files"%len(diffs)
+    for (path,contents) in diffs.iteritems():
+        if options.verbose:
+            print "= = = = =  Diffs in path %s"%path
+            for line in contents: print line
+        else:
+            print "Diffs in path %s (%d lines)"%(path,len(contents))
+            
+
+left_default=os.path.expanduser("~/git/sfa")
+right_default=os.path.expanduser("~/git/sfa-generic")
+
+def main ():
+    parser=OptionParser()
+    parser.add_option("-g","--git",action='store_true',dest='git',default=False,
+                      help="run git pull before diffing")
+    parser.add_option("-l","--left",action='store',dest='left_dir',default=left_default,
+                      help="left dir, default=%s"%left_default)
+    parser.add_option("-r","--right",action='store',dest='right_dir',default=right_default,
+                      help="right dir, default=%s"%right_default)
+    parser.add_option("-v","--verbose",action='store_true',dest='verbose',default=False,
+                      help="Show actual diff contents")
+    (options,args)=parser.parse_args()
+    if options.git:
+        git_update(options.left_dir)
+        git_update(options.right_dir)
+    run_diff(options)
+
+if __name__ == "__main__":
+    main()