#!/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) # this is ad hoc for sfa diffing .. excludes=[ "*.git*", "*~" ] excludes+= [ "*.pyc", "*.png", "*.pdf", "*.out" , "*.DS_Store", "*.lint" ] excludes+= [ "listfiles.sh", "python.*" ] excludes+= [ "*HEAD", "*txt" ] excludes+= [ "*slab*", "senslab" ] 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.*) %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()