#!/usr/bin/pythonimportsubprocess,re,sysfromxml.etreeimportElementTreedefidentify(db,patch):"""Return revision number and branch of a patch; either value may become None."""m=re.search(r'---.* ([0-9]+)\)',patch)ifnotm:returnNonerev=int(m.group(1))returnrevdeffind_branch(db,rev):"""Return the branch name for a given revision, or None."""c=db.cursorc.execute('select branch from svnbranch where rev=%s',(rev,))branch=c.fetchone()ifbranch:returnbranch[0]# may need to cache more revisionsreturnfill_revs(db,lookfor=rev)defaddfiles(cursor,files):"""Add all files to fileprefix that aren't there, in all prefix/suffix combinations."""to_add=[]forfinfiles:cursor.execute("select count(*) from fileprefix ""where prefix='' and suffix=%s",(f,))ifcursor.fetchone()[0]>0:continueparts=f.split('/')foriinrange(len(parts)):prefix='/'.join(parts[:i])ifi:prefix+='/'suffix='/'.join(parts[i:])to_add.append((prefix,suffix))cursor.executemany("insert into fileprefix(prefix, suffix) ""values(%s, %s)",to_add)deffill_revs(db,lookfor=None):"""Initialize/update svnbranch table. If lookfor is given, return its branch, or None if that cannot be determined."""result=Nonec=db.cursorc.execute('select max(rev) from svnbranch')start=c.fetchone()[0]ifnotstart:start=1else:start=start+1iflookforandlookfor<start:# revision is not in databasereturnNonep=subprocess.Popen(['svn','log','-r%s:HEAD'%start,'--xml','-v','http://svn.python.org/projects'],stdout=subprocess.PIPE,stderr=open('/dev/null','w'))data=p.stdout.read()ifp.wait()!=0:# svn log failedreturnNonexml=ElementTree.fromstring(data)files=set()forentryinxml.findall('logentry'):rev=int(entry.get('revision'))paths=[p.textforpinentry.findall('paths/path')]ifnotpaths:continuepath=paths[0]if(notpath.startswith('/python')or# The count may be smaller on the revision that created /python# or the branchpath.count('/')<3):continuebranch=path[len('/python'):]ifbranch.startswith('/trunk'):branch='/trunk'else:d1,d2=branch.split('/',3)[1:3]branch='/'+d1+'/'+d2ppath='/python'+branchforpinpaths:ifnotp.startswith(ppath):# inconsistent commitbreakelse:ifbranchin('/trunk','/branches/py3k'):# Add all files that ever existed on the main trunksforpinpaths:files.add(p[len(ppath)+1:])c.execute('insert into svnbranch(rev, branch) values(%s, %s)',(rev,branch))iflookfor==rev:result=branchaddfiles(c,files)db.commit()returnresult# this runs as a cron job every 30minif__name__=='__main__':# manual setup:# create table svnbranch(rev integer primary key, branch text);# create table fileprefix(prefix text, suffix text);# create index fileprefix_suffix on fileprefix(suffix);# then run this once in the instance directorysys.path.append('/home/roundup/lib/python2.5/site-packages')importroundup.instancetracker=roundup.instance.open('.')db=tracker.open('admin')#db.cursor.execute('delete from svnbranch')fill_revs(db)