#!/usr/bin/env python # interactively apply each hunk of a patch. # 061120: # Missing hunks when hitting --- lines while building hunks # improve visual # import sys; import re; import string; import os; def usage(): print "ipatch.py [-o \"\"] [-u ] " print print "\tInteractively apply patch hunk by hunk"; print print "\t-o : options passed to 'patch' command. Don't pass 'dry-run'." print "\t-u : unapplied patch hunks are put into this file." def error(msg): print "Error : %s" % (msg); sys.exit(-1); def spit_hunk(file, hunk, no) : global patch_opts; global unused_file; f = open("/tmp/ipatch-temp.patch", "w"); f.write(file + hunk); f.close(); print print "=============================================================="; print file + hunk; while 1==1: print print "-------------------"; print "Press 'y' to apply, 't' to try, or to skip the hunk ..." c = sys.stdin.readline(); c=string.strip(c); print if c == 'y': sys.stdout.flush(); cmd = "patch " + patch_opts + " < /tmp/ipatch-temp.patch"; ret=os.system(cmd); sys.stdout.flush(); if ret!=0 : print "patching hunk #" + `no` + " failed ..."; if no == 1: unused_file.write(file + hunk); else: unused_file.write(hunk); print "-------------------"; print "Press to continue ..."; c = sys.stdin.readline(); break; elif c == 't': sys.stdout.flush(); cmd = "patch " + patch_opts + " --dry-run < /tmp/ipatch-temp.patch"; os.system(cmd); sys.stdout.flush(); else: print "skipping hunk #" + `no` + " ..."; if no == 1: unused_file.write(file + hunk); else: unused_file.write(hunk); break; if (len(sys.argv)%2 !=0) or sys.argv[1] == "-h": usage(); sys.exit(); # check options patch_opts=""; unused_fname="/tmp/ipatch-unused.patch"; for i in (1, 3): if len(sys.argv) == i+1: break; if sys.argv[i] == "-o": patch_opts = sys.argv[i+1]; elif sys.argv[i] == "-u": unused_fname = sys.argv[i+1]; file=open(sys.argv[len(sys.argv)-1], 'r'); unused_file=open(unused_fname, 'w'); state="need_file"; file_header=""; num_lines=0; for l in file.readlines(): num_lines+=1; if state == "need_file" and (re.match(r"^--- ", l) or re.match(r"^\+\+\+ ", l)) : file_header = l; state = "need_file_1"; elif state == "need_file_1" : if (re.match(r"^--- ", l) or re.match(r"^\+\+\+ ", l)) : file_header = file_header + l; state = "need_hunk"; num_hunks=0; else : msg = "Unexpected line at line " + `num_lines` + ". State is need_file_1"; error(msg); elif state == "need_hunk" : if re.match(r"^@@ .* @@", l): hunk = l; state = "build_hunk"; elif state == "build_hunk" : if re.match(r"^@@ .* @@", l): num_hunks +=1; spit_hunk(file_header, hunk, num_hunks); hunk = l; state = "build_hunk"; elif (re.match(r"^--- ", l) or re.match(r"^\+\+\+ ", l)) : num_hunks +=1; spit_hunk(file_header, hunk, num_hunks); file_header = l; state = "need_file_1"; elif (not re.match(r"^diff ", l)) : # skip auxilillary diff lines hunk += l; if state == "build_hunk": num_hunks +=1; spit_hunk(file_header, hunk, num_hunks); file.close(); unused_file.close();