Make changes from last cset 474b415433a1 available to 0.9.3
# keyword.py - keyword expansion for mercurial# $Id$'''keyword expansion hack against the grain of a DSCMThis extension lets you expand RCS/CVS-like keywords in a Mercurialrepository.There are many good reasons why this is not needed in a distributedSCM, still it may be useful in very small projects based on singlefiles (like LaTeX packages), that are mostly addressed to an audiencenot running a version control system.Supported $keywords$ are: Revision: changeset id Author: full username Date: %a %b %d %H:%M:%S %Y %z $ RCSFile: basename,v Source: /path/to/basename,v Id: basename,v csetid %Y-%m-%d %H:%M:%S %s shortname Header: /path/to/basename,v csetid %Y-%m-%d %H:%M:%S %s shortnameSimple setup in hgrc: # enable extension # keyword.py in hgext folder, specify full path otherwise hgext.keyword = # filename patterns for expansion are configured in this section [keyword] **.py = expand ...'''frommercurial.nodeimport*frommercurial.i18nimportgettextas_frommercurialimportcontext,filelog,revlog,utilimportos.path,rere_kw=re.compile(r'\$(Id|Header|Author|Date|Revision|RCSFile|Source)[^$]*?\$')defkwexpand(matchobj,repo,path,changeid=None,fileid=None,filelog=None):'''Called by kwrepo.commit and kwfilelog.read. Sets supported keywords as local variables and evaluates them to their expansion if matchobj is equal to string representation.'''c=context.filectx(repo,path,changeid=changeid,fileid=fileid,filelog=filelog)date=c.date()Revision=c.changectx()Author=c.user()RCSFile=os.path.basename(path)+',v'Source=repo.wjoin(path)+',v'Date=util.datestr(date=date)revdateauth='%s%s%s'%(Revision,util.datestr(date=date,format=util.defaultdateformats[0]),util.shortuser(Author))Header='%s%s'%(Source,revdateauth)Id='%s%s'%(RCSFile,revdateauth)return'$%s: %s $'%(matchobj.group(1),eval(matchobj.group(1)))defkwfmatches(ui,repo,files):'''Selects candidates for keyword substitution configured in keyword section in hgrc.'''files=[fforfinfilesifnotf.startswith('.hg')]ifnotfiles:return[]candidates=[]fmatchers=[util.matcher(repo.root,'',[pat],[],[])[1]forpat,optinui.configitems('keyword')ifopt=='expand']forfinfiles:formfinfmatchers:ifmf(f):candidates.append(f)breakreturncandidatesdefreposetup(ui,repo):ifnotrepo.local():returnclasskwrepo(repo.__class__):deffile(self,f):iff[0]=='/':f=f[1:]returnfilelog.filelog(self.sopener,f,self,self.revlogversion)defcommit(self,files=None,text="",user=None,date=None,match=util.always,force=False,lock=None,wlock=None,force_editor=False,p1=None,p2=None,extra={}):commit=[]remove=[]changed=[]use_dirstate=(p1isNone)# not rawcommitextra=extra.copy()ifuse_dirstate:iffiles:forfinfiles:s=self.dirstate.state(f)ifsin'nmai':commit.append(f)elifs=='r':remove.append(f)else:ui.warn(_("%s not tracked!\n")%f)else:changes=self.status(match=match)[:5]modified,added,removed,deleted,unknown=changescommit=modified+addedremove=removedelse:commit=filesifuse_dirstate:p1,p2=self.dirstate.parents()update_dirstate=Trueelse:p1,p2=p1,p2ornullidupdate_dirstate=(self.dirstate.parents()[0]==p1)c1=self.changelog.read(p1)c2=self.changelog.read(p2)m1=self.manifest.read(c1[0]).copy()m2=self.manifest.read(c2[0])ifuse_dirstate:branchname=self.workingctx().branch()try:branchname=branchname.decode('UTF-8').encode('UTF-8')exceptUnicodeDecodeError:raiseutil.Abort(_('branch name not in UTF-8!'))else:branchname=""ifuse_dirstate:oldname=c1[5].get("branch","")# stored in UTF-8ifnotcommitandnotremoveandnotforceandp2==nullidand \branchname==oldname:ui.status(_("nothing changed\n"))returnNonexp1=hex(p1)ifp2==nullid:xp2=''else:xp2=hex(p2)self.hook("precommit",throw=True,parent1=xp1,parent2=xp2)ifnotwlock:wlock=self.wlock()ifnotlock:lock=self.lock()tr=self.transaction()# check in filesnew={}linkrev=self.changelog.count()commit.sort()forfincommit:ui.note(f+"\n")try:new[f]=self.filecommit(f,m1,m2,linkrev,tr,changed)m1.set(f,util.is_exec(self.wjoin(f),m1.execf(f)))exceptIOError:ifuse_dirstate:ui.warn(_("trouble committing %s!\n")%f)raiseelse:remove.append(f)# update manifestm1.update(new)remove.sort()forfinremove:iffinm1:delm1[f]mn=self.manifest.add(m1,tr,linkrev,c1[0],c2[0],(new,remove))# add changesetnew=new.keys()new.sort()user=userorui.username()ifnottextorforce_editor:edittext=[]iftext:edittext.append(text)edittext.append("")edittext.append("HG: user: %s"%user)ifp2!=nullid:edittext.append("HG: branch merge")edittext.extend(["HG: changed %s"%fforfinchanged])edittext.extend(["HG: removed %s"%fforfinremove])ifnotchangedandnotremove:edittext.append("HG: no files changed")edittext.append("")# run editor in the repository rootolddir=os.getcwd()os.chdir(self.root)text=ui.edit("\n".join(edittext),user)os.chdir(olddir)lines=[line.rstrip()forlineintext.rstrip().splitlines()]whilelinesandnotlines[0]:dellines[0]ifnotlines:returnNonetext='\n'.join(lines)ifbranchname:extra["branch"]=branchnamen=self.changelog.add(mn,changed+remove,text,tr,p1,p2,user,date,extra)self.hook('pretxncommit',throw=True,node=hex(n),parent1=xp1,parent2=xp2)# substitute keywordsforfinkwfmatches(ui,self,changed):data=self.wfile(f).read()ifnotutil.binary(data):data,kwct=re_kw.subn(lambdam:kwexpand(m,self,f,changeid=hex(n)),data)ifkwct:ui.debug(_('overwriting %s expanding keywords\n'%f))self.wfile(f,'w').write(data)tr.close()ifuse_dirstateorupdate_dirstate:self.dirstate.setparents(n)ifuse_dirstate:self.dirstate.update(new,"n")self.dirstate.forget(removed)self.hook("commit",node=hex(n),parent1=xp1,parent2=xp2)returnnclasskwfilelog(filelog.filelog):''' Superclass over filelog to customize it's read, add, cmp methods. Keywords are "stored" unexpanded, and expanded on reading. '''def__init__(self,opener,path,repo,defversion=revlog.REVLOG_DEFAULT_VERSION):super(kwfilelog,self).__init__(opener,path,defversion)self._repo=repoself._path=pathdefiskwcandidate(self,data):'''Decides whether to act on keywords.'''return(kwfmatches(ui,self._repo,[self._path])andnotutil.binary(data))defread(self,node):'''Substitutes keywords when reading filelog.'''data=super(kwfilelog,self).read(node)ifself.iskwcandidate(data):returnre_kw.sub(lambdam:kwexpand(m,self._repo,self._path,fileid=node,filelog=self),data)returndatadefadd(self,text,meta,tr,link,p1=None,p2=None):'''Removes keyword substitutions when adding to filelog.'''ifself.iskwcandidate(text):text=re_kw.sub(r'$\1$',text)returnsuper(kwfilelog,self).add(text,meta,tr,link,p1=None,p2=None)defcmp(self,node,text):'''Removes keyword substitutions for comparison.'''ifself.iskwcandidate(text):text=re_kw.sub(r'$\1$',text)returnsuper(kwfilelog,self).cmp(node,text)filelog.filelog=kwfilelogrepo.__class__=kwrepo