#!/usr/bin/env python2.2 # get_diff_helper.py, Version 1.0, Raimar Falke import sys,re,time,pwd,os, string def log(str): sys.stderr.write(str+"\n") def parse_date(date): old=list(time.strptime(date, "%Y/%m/%d %H:%M:%S")) old[8]=0 result=time.mktime(old) result=result-time.timezone if 0: new=list(time.gmtime(result)) if old!=new: print old,new assert 0 return result def parse(branch,name,read_entries): lines=open(name).readlines() last_line=lines[-1] assert last_line=='=============================================================================\n',repr(last_line) mo=re.search("(?s)(?m)^symbolic names:(.*)keyword substitution","".join(lines)) assert mo symbolic_names={} if mo.group(1).strip(): for tag_name,rev in map(lambda x:x.strip().split(":"),mo.group(1).strip().split("\n")): rev=map(int,rev.strip().split(".")) # the others are just tags if len(rev)>2 and rev[2]==0: # 1.19.0.2 -> 1.19.2 assert len(rev)==4 rev[2]=2 del rev[3] symbolic_names[tag_name]=rev mo=re.search("Working file: (.*)$",lines[2]) filename=mo.group(1) filename=re.sub("^\./","",filename) revisions="".join(lines[:-1]).split("\n----------------------------\n")[1:] tmp_entries=[] for revision in revisions: lines=revision.split("\n") entry={} entry["filename"]=filename mo=re.search("^revision (.*)$",lines[0]) entry["revision"]=mo.group(1) entry["num_revision"]=map(int,entry["revision"].split(".")) for j in lines[1].split("; "): key,value=map(lambda x:x.strip(), j.split(": ")) entry[key]=value entry["date"]=parse_date(entry["date"]) entry["msg"]="\n".join(lines[2:]) #print entry tmp_entries.append(entry) tmp_entries.sort(lambda x,y: cmp(x["num_revision"],y["num_revision"])) #print "branch=%s name=%s branches=%s"%(branch,name,symbolic_names) for entry in tmp_entries: add=0 if branch=="HEAD": if len(entry["num_revision"])==2: add=1 elif not symbolic_names.has_key(branch): pass # this file was added later else: if entry["num_revision"] < symbolic_names[branch] or \ (len(entry["num_revision"])>2 and \ entry["num_revision"][0:3]==symbolic_names[branch]): add=1 #print " num_revision=%s add=%d"%(entry["num_revision"],add) if add: read_entries.append(entry) def merge(entries): result=[] for e in entries: new_commit=1 if len(result)>0: same_author=e["author"]==result[-1]["author"] same_msg=e["msg"].strip()==result[-1]["msg"].strip() if same_author and same_msg: result[-1]["filenames"].append((e["filename"], e["num_revision"])) result[-1]["last_date"]=e["date"] new_commit=0 if new_commit: commit={} commit["msg"]=e["msg"] commit["author"]=e["author"] commit["filenames"]=[(e["filename"],e["num_revision"])] commit["first_date"]=e["date"] commit["last_date"]=e["date"] result.append(commit) return result def read_log_files(branch, filenames): entries=[] log("Reading %d files"%(len(filenames))) for i in filenames: parse(branch, i,entries) log("Read %d revisions"%(len(entries))) return entries def my_wrap(str, max_size): all = [] line = "" for l in str.split(): if len(line+l) >= max_size: all = all + [line] line = '' line = line + (line and ' ') + l all = all + [line] all=map(lambda x:"\t"+x, all) return "\n".join(all) def print_short_commit(i): print "%10s: %s | %s"%(i["author"], i["msg"][0:20].replace("\n"," ").ljust(20), " ".join(i["filenames"])[0:40]) def print_changelog_commit(i): i["filenames"].sort() first=time.strftime("%a %b %d %H:%M:%S %Y",time.gmtime(i["first_date"])) last=time.strftime("%a %b %d %H:%M:%S %Y",time.gmtime(i["last_date"])) name=i["author"] print "%s-%s %s:"%(first,last,name) print for x in i["filenames"]: print " "+format(x) print paragraphs=i["msg"].split("\n\n") for i in paragraphs: print my_wrap(i, 65) print def format(t): name=t[0] rev=".".join(map(str,t[1])) return "%s:%s"%(name, rev) def unformat(s): name,rev=s.split(":") rev=map(int,rev.strip().split(".")) return (name,rev) def print_cvs_diff_commands(commit): cmds=open("get_diff_cvs_commands","w") for name,rev in commit["filenames"]: prev_rev=rev[:] prev_rev[-1]-=1 rev=".".join(map(str,rev)) prev_rev=".".join(map(str,prev_rev)) cmds.write("-N -r %s -r %s %s\n"%(prev_rev, rev, name)) def usage(): log("get_diff [-r file:revision] | [-d date]") sys.exit(1) def main(): branch="HEAD" req_rev=None req_date=None if len(sys.argv)!=3: usage() if sys.argv[1] == "-r": req_rev=unformat(sys.argv[2]) elif sys.argv[1] == "-d": req_date=parse_date(sys.argv[2]) else: usage() log_files=sys.stdin.readlines() log_files=map(lambda x: string.rstrip(x), log_files) read_entries=read_log_files(branch, log_files) read_entries.sort(lambda x,y: cmp(x["date"],y["date"])) if req_rev: l=[] for rev in read_entries: if rev["filename"] == req_rev[0] and \ rev["num_revision"]==req_rev[1]: l.append(rev) if len(l)==0: log("Can't find the given file or revision.") sys.exit(1) req_date=l[0]["date"] from_date=req_date-(12*60*60) to_date=req_date+(12*60*60) read_entries=filter(lambda x: from_date<=x["date"]<=to_date,read_entries) log("%d revisions after date filtering"%len(read_entries)) if 0: for i in read_entries: print "%10s: %s | %s"%(i["author"], i["msg"][0:20].replace("\n"," ").ljust(20), i["filename"]) commits=merge(read_entries) log("Merged to %d commits"%len(commits)) if 0: for i in commits: print "%10s: %s | %s"%(i["author"], i["msg"][0:20].replace("\n"," ").ljust(20), " ".join(map(format,i["filenames"]))[0:80]) commits=filter(lambda x: x["first_date"]<=req_date<=x["last_date"],commits) if len(commits)==0: log("No commit at the given time") sys.exit(1) assert len(commits)==1,repr(commits) print_changelog_commit(commits[0]) print_cvs_diff_commands(commits[0]) if __name__=="__main__": main()