#!/usr/local/bin/python # import sys, os, string, re # This func corresponds to p4 diff2 with the -dn switch def extract_metrics_counts_rcs( depot_root, label_one, label_two ): # Does a p4 changes depot_root@label_one depot_root@label_two # depot_root is used to limit the diff range to a single "project" # or something even smaller.. like a single file # we then parse the output and add up the totals # quote the 2 params for the cases where the depot path contains a space command = 'p4 diff2 -dn \"' + depot_root + label_one + '\" \"' + depot_root + label_two + '\"' lines_added = 0 lines_changed = 0 lines_deleted = 0 #sys.stdout.write('Extraction function using ' + command +' \n' ) # break the line up according to... # sample line: a85 2 # operation (line)location (Number of lines affected)count p = re.compile( r'^([ad])([0-9]+) (\d+)' ) for line in os.popen( command,'r').readlines(): tmp = line[0:1] if tmp == 'a' or tmp == 'd': # only do this if we have a match otherwise groups() will blow chunks diffing an rtf m = p.match( line ) if m: (operation, location, count) = re.match( r'^([ad])([0-9]+) (\d+)', line).groups() #sys.stdout.write( '>' + operation + '< >' + location + '< >' + count + '<\n' ) if tmp == 'a': lines_added = lines_added + int( count ) elif tmp == 'd': lines_deleted = lines_deleted + int( count ) return lines_added, lines_deleted # This func corresponds to p4 diff2 with the -dc switch def extract_metrics_counts_context( depot_root, label_one, label_two ): # Does a p4 changes depot_root@label_one depot_root@label_two # depot_root is used to limit the diff range to a single "project" # or something even smaller.. like a single file # we then parse the output and add up the totals # quote the 2 params for the cases where the depot path contains a space command = 'p4 diff2 -dc \"' + depot_root + label_one + '\" \"' + depot_root + label_two + '\"' lines_added = 0 lines_changed = 0 lines_deleted = 0 #sys.stdout.write('Extraction function using ' + command +' \n' ) for line in os.popen( command,'r').readlines(): # sample line: Change number on date by name@machine 'comment' # dummy ch# #sys.stdout.write( line + '\n' ) tmp = line[0:1] if tmp == '+': lines_added = lines_added + 1 elif tmp == '-': lines_deleted = lines_deleted + 1 elif tmp == '!': lines_changed = lines_changed +1 return lines_added,lines_changed,lines_deleted def extract_metrics_counts_summary( depot_root, label_one, label_two ): # Does a p4 changes depot_root@label_one depot_root@label_two # depot_root is used to limit the diff range to a single "project" # or something even smaller.. like a single file # we then parse the output and add up the totals # quote the 2 params for the cases where the depot path contains a space command = 'p4 diff2 -ds \"' + depot_root + label_one + '\" \"' + depot_root + label_two + '\"' lines_added = 0 add_chunks = 0 lines_deleted = 0 delete_chunks = 0 lines_changed = 0 change_chunks = 0 extra_data = 0 #sys.stdout.write('Extraction function using ' + command +' \n' ) # This will match lines starting with exp1 = re.compile( r'^["add""deleted""changed]"' ) # # The next 3 eat the add deleted and changed lines # it could be one expression I suppose # exp2 = re.compile( r'^(add) (\d+) (chunks) (\d+)' ) exp3 = re.compile( r'^(deleted) (\d+) (chunks) (\d+)' ) exp4 = re.compile( r'^(changed) (\d+) (chunks) (\d+) / (\d+)' ) for line in os.popen( command,'r').readlines(): # only do this if we have a match m2 = exp2.search( line ) m3 = exp3.search( line ) m4 = exp4.search( line ) if m2: ( operation, count1, chunks, count2 ) = m2.groups() add_chunks = add_chunks + int( count1 ) lines_added = lines_added + int( count2 ) #sys.stdout.write( count2 + '\n' ) elif m3: ( operation, count1, chunks, count2 ) = m3.groups() delete_chunks = delete_chunks + int( count1 ) lines_deleted = lines_deleted + int( count2 ) #sys.stdout.write( count2 + '\n' ) elif m4: ( operation, count1, chunks, count2, count3 ) = m4.groups() change_chunks = change_chunks + int( count1 ) extra_data = extra_data + int( count2 ) lines_changed = lines_changed + int( count3 ) #sys.stdout.write( count3 + '\n' ) return lines_added,add_chunks,lines_deleted,delete_chunks,lines_changed,change_chunks, extra_data # This func corresponds to p4 diff2 with the -du switch def extract_metrics_counts_unified( depot_root, label_one, label_two ): # Does a p4 changes depot_root@label_one depot_root@label_two # depot_root is used to limit the diff range to a single "project" # or something even smaller.. like a single file # we then parse the output and add up the totals # quote the 2 params for the cases where the depot path contains a space command = 'p4 diff2 -du \"' + depot_root + label_one + '\" \"' + depot_root + label_two + '\"' lines_added = 0 lines_deleted = 0 #sys.stdout.write('Extraction function using ' + command +' \n' ) for line in os.popen( command,'r').readlines(): # sample line: Change number on date by name@machine 'comment' # dummy ch# #sys.stdout.write( line + '\n' ) tmp = line[0:1] if tmp == '+': lines_added = lines_added + 1 elif tmp == '-': lines_deleted = lines_deleted + 1 return lines_added, lines_deleted # This func corresponds to p4 diff2 with no switchs def extract_metrics_counts_flat( depot_root, label_one, label_two ): # Does a p4 changes depot_root@label_one depot_root@label_two # depot_root is used to limit the diff range to a single "project" # or something even smaller.. like a single file # we then parse the output and add up the totals # quote the 2 params for the cases where the depot path contains a space command = 'p4 diff2 \"' + depot_root + label_one + '\" \"' + depot_root + label_two + '\"' lines_added = 0 lines_deleted = 0 lines_changed = 0 #sys.stdout.write('Extraction function using ' + command +' \n' ) expFile = re.compile( r'^====' ) # The next 4 eat the add deleted and changed lines # it could be one expression I suppose # exp1 = re.compile( r'^(\d+)([acd])(\d+)' ) exp2 = re.compile( r'^(\d+),(\d+)([acd])(\d+)' ) exp3 = re.compile( r'^(\d+)([acd])(\d+),(\d+)' ) exp4 = re.compile( r'^(\d+),(\d+)([acd])(\d+),(\d+)' ) for line in os.popen( command,'r').readlines(): # only do this if we have a match m1 = exp1.search( line ) m2 = exp2.search( line ) m3 = exp3.search( line ) m4 = exp4.search( line ) if m4: ( count1, count2, operation, count3, count4 ) = m4.groups() mLine = expFile.match( prev_line ) if mLine: sys.stdout.write( prev_line + '\n' ) sys.stdout.write( count1 + ' ' + count2 + ' ' + operation + ' ' + count3 + ' ' + count4 + '\n' ) elif m3: ( count1, operation, count2, count3 )= m3.groups() mLine = expFile.match( prev_line ) if mLine: sys.stdout.write( prev_line + '\n' ) sys.stdout.write( count1 + ' ' + operation + ' ' + count2 + ' ' + count3 + '\n' ) elif m2: ( count1, count2, operation, count3 ) = m2.groups() mLine = expFile.match( prev_line ) if mLine: sys.stdout.write( prev_line + '\n' ) sys.stdout.write( count1 + ' ' + count2 + ' ' + operation + ' ' + count3 + '\n' ) elif m1: ( count1, operation, count2 ) = m1.groups() mLine = expFile.match( prev_line ) if mLine: sys.stdout.write( prev_line + '\n' ) sys.stdout.write( count1 + ' ' + operation + ' ' + count2 + '\n' ) prev_line = line return lines_added, lines_deleted, lines_changed # # This script takes a depot path and two labels (like @jakcalope.20 ) # OR two date-time combos (like @1999/02/02 ) # # The output then gives you the counts of lines changed deleted or added # by each of the various "p4 diff2 -d?" formats. (metrics) # # # Main body of program # # depot_location = sys.argv[1] diff_label1 = "@" + sys.argv[2] diff_label2 = "@" + sys.argv[3] sys.stdout.write( 'Starting processing....\n\n' ) # fyi sys.stdout.write('Start point ' + diff_label1 + ' End Point ' + diff_label2 + '\n' ) sys.stdout.write('Depot Range ' + depot_location + '\n\n' ) #call the diff with the RCS flags # # #adds = changes = deletes = 0 ( adds, deletes) = extract_metrics_counts_rcs( depot_location, diff_label1, diff_label2 ) sys.stdout.write( 'Metrics via RCS diff method Lines Added --> ' + `adds` + '\n' ) sys.stdout.write( ' Lines Deleted--> ' + `deletes` + '\n\n' ) #call the diff with the context flags # # #adds = changes = deletes = 0 #( adds, changes, deletes) = extract_metrics_counts_context( depot_location, diff_label1, diff_label2 ) #sys.stdout.write( 'Metrics via Context diff method Lines Added --> ' + `adds` + '\n' ) #sys.stdout.write( ' Lines Changed--> ' + `changes` + '\n' ) #sys.stdout.write( ' Lines Deleted--> ' + `deletes` + '\n\n' ) #call the diff with the summary flags # # adds = changes = deletes = 0 ( adds, addchunks, deletes, deletechunks, changes, changechunks, extra ) = extract_metrics_counts_summary( depot_location, diff_label1, diff_label2 ) sys.stdout.write( 'Metrics via Summary diff method Add --> ' + `addchunks` + ' Chunks\n' ) sys.stdout.write( ' ' + `adds` + ' Lines\n' ) sys.stdout.write( ' Deleted--> ' + `deletechunks` + ' Chunks\n' ) sys.stdout.write( ' ' + `deletes` + ' Lines\n' ) sys.stdout.write( ' Changed--> ' + `changechunks` + ' Chunks\n' ) sys.stdout.write( ' ' + `changes` + ' Lines\n' ) sys.stdout.write( '\n\n\n\n' ) #call the diff with the unified flags # # #adds = changes = deletes = 0 #( adds, deletes) = extract_metrics_counts_unified( depot_location, diff_label1, diff_label2 ) #sys.stdout.write( 'Metrics via Unified diff method Lines Added --> ' + `adds` + '\n' ) #sys.stdout.write( ' Lines Deleted--> ' + `deletes` + '\n\n' )