Mercurial and Git clients can push and pull from this alias URL to interact with this repository. You can change to which repository an alias points by going to the Aliases link on the project page.
# shelve.py## Copyright 2007 Bryan O'Sullivan <bos@serpentine.com># Copyright 2007 TK Soh <teekaysoh@gmailcom>## This software may be used and distributed according to the terms of# the GNU General Public License, incorporated herein by reference.'''interactive change selection to set aside that may be restored later'''importcopyimportcStringIOimporterrnoimportoperatorimportosimportreimportshutilimporttempfilefrommercurialimportcmdutil,commands,cmdutil,hg,mdiff,patch,revlogfrommercurialimportutil,fancyoptsfromthgutil.i18nimport_fromthgutilimporthgliblines_re=re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')definternalpatch(patchobj,ui,strip,cwd,reverse=False,files={}):"""use builtin patch to apply <patchobj> to the working directory. returns whether patch was applied with fuzz factor. Adapted from patch.internalpatch() to support reverse patching. """try:fp=file(patchobj,'rb')exceptTypeError:fp=patchobjifcwd:curdir=os.getcwd()os.chdir(cwd)try:ret=patch.applydiff(ui,fp,files,strip=strip,reverse=reverse)finally:ifcwd:os.chdir(curdir)ifret<0:raisepatch.PatchErrorreturnret>0defscanpatch(fp):lr=patch.linereader(fp)defscanwhile(first,p):lines=[first]whileTrue:line=lr.readline()ifnotline:breakifp(line):lines.append(line)else:lr.push(line)breakreturnlineswhileTrue:line=lr.readline()ifnotline:breakifline.startswith('diff --git a/'):defnotheader(line):s=line.split(None,1)returnnotsors[0]notin('---','diff')header=scanwhile(line,notheader)fromfile=lr.readline()iffromfile.startswith('---'):tofile=lr.readline()header+=[fromfile,tofile]else:lr.push(fromfile)yield'file',headerelifline[0]==' ':yield'context',scanwhile(line,lambdal:l[0]in' \\')elifline[0]in'-+':yield'hunk',scanwhile(line,lambdal:l[0]in'-+\\')else:m=lines_re.match(line)ifm:yield'range',m.groups()else:raisepatch.PatchError(_('unknown patch content: %r')%line)classheader(object):diff_re=re.compile('diff --git a/(.*) b/(.*)$')allhunks_re=re.compile('(?:index|new file|deleted file) ')pretty_re=re.compile('(?:new file|deleted file) ')special_re=re.compile('(?:index|new file|deleted|copy|rename) ')def__init__(self,header):self.header=headerself.hunks=[]defbinary(self):forhinself.header:ifh.startswith('index '):returnTruedefselpretty(self,selected):str=''forhinself.header:ifh.startswith('index '):str+=_('this modifies a binary file (all or nothing)\n')breakifself.pretty_re.match(h):str+=hglib.toutf(h)ifself.binary():str+=_('this is a binary file\n')breakifh.startswith('---'):hunks=len(self.hunks)shunks,lines,slines=0,0,0fori,hinenumerate(self.hunks):lines+=h.added+h.removedifselected(i):shunks+=1slines+=h.added+h.removedstr+="<span foreground='#000088'>"str+=_('total: %d hunks (%d changed lines); ''selected: %d hunks (%d changed lines)')%(hunks,lines,shunks,slines)str+="</span>"breakstr+=hglib.toutf(h)returnstrdefpretty(self,fp):forhinself.header:ifh.startswith('index '):fp.write(_('this modifies a binary file (all or nothing)\n'))breakifself.pretty_re.match(h):fp.write(h)ifself.binary():fp.write(_('this is a binary file\n'))breakifh.startswith('---'):fp.write(_('%d hunks, %d lines changed\n')%(len(self.hunks),sum([h.added+h.removedforhinself.hunks])))breakfp.write(h)defwrite(self,fp):fp.write(''.join(self.header))defallhunks(self):forhinself.header:ifself.allhunks_re.match(h):returnTruedeffiles(self):fromfile,tofile=self.diff_re.match(self.header[0]).groups()iffromfile==tofile:return[fromfile]return[fromfile,tofile]deffilename(self):returnself.files()[-1]def__repr__(self):return'<header %s>'%(' '.join(map(repr,self.files())))defspecial(self):forhinself.header:ifself.special_re.match(h):returnTruedef__cmp__(self,other):returncmp(repr(self),repr(other))defcountchanges(hunk):add=len([hforhinhunkifh[0]=='+'])rem=len([hforhinhunkifh[0]=='-'])returnadd,remclasshunk(object):maxcontext=3def__init__(self,header,fromline,toline,proc,before,hunk,after):deftrimcontext(number,lines):delta=len(lines)-self.maxcontextifFalseanddelta>0:returnnumber+delta,lines[:self.maxcontext]returnnumber,linesself.header=headerself.fromline,self.before=trimcontext(fromline,before)self.toline,self.after=trimcontext(toline,after)self.proc=procself.hunk=hunkself.added,self.removed=countchanges(self.hunk)defwrite(self,fp):delta=len(self.before)+len(self.after)ifself.afterandself.after[-1]=='\\ No newline at end of file\n':delta-=1fromlen=delta+self.removedtolen=delta+self.addedfp.write('@@ -%d,%d +%d,%d @@%s\n'%(self.fromline,fromlen,self.toline,tolen,self.procand(' '+self.proc)))fp.write(''.join(self.before+self.hunk+self.after))pretty=writedeffilename(self):returnself.header.filename()def__repr__(self):return'<hunk %r@%d>'%(self.filename(),self.fromline)def__cmp__(self,other):returncmp(repr(self),repr(other))defparsepatch(fp):classparser(object):def__init__(self):self.fromline=0self.toline=0self.proc=''self.header=Noneself.context=[]self.before=[]self.hunk=[]self.stream=[]defaddrange(self,(fromstart,fromend,tostart,toend,proc)):self.fromline=int(fromstart)self.toline=int(tostart)self.proc=procdefaddcontext(self,context):ifself.hunk:h=hunk(self.header,self.fromline,self.toline,self.proc,self.before,self.hunk,context)self.header.hunks.append(h)self.stream.append(h)self.fromline+=len(self.before)+h.removedself.toline+=len(self.before)+h.addedself.before=[]self.hunk=[]self.proc=''self.context=contextdefaddhunk(self,hunk):ifself.context:self.before=self.contextself.context=[]self.hunk=hunkdefnewfile(self,hdr):self.addcontext([])h=header(hdr)self.stream.append(h)self.header=hdeffinished(self):self.addcontext([])returnself.streamtransitions={'file':{'context':addcontext,'file':newfile,'hunk':addhunk,'range':addrange},'context':{'file':newfile,'hunk':addhunk,'range':addrange},'hunk':{'context':addcontext,'file':newfile,'range':addrange},'range':{'context':addcontext,'hunk':addhunk},}p=parser()state='context'fornewstate,datainscanpatch(fp):try:p.transitions[state][newstate](p,data)exceptKeyError:raisepatch.PatchError(_('unhandled transition: %s -> %s')%(state,newstate))state=newstatereturnp.finished()deffilterpatch(ui,chunks):chunks=list(chunks)chunks.reverse()seen={}defconsumefile():consumed=[]whilechunks:ifisinstance(chunks[-1],header):breakelse:consumed.append(chunks.pop())returnconsumedresp_all=[None]resp_file=[None]applied={}defprompt(query):ifresp_all[0]isnotNone:returnresp_all[0]ifresp_file[0]isnotNone:returnresp_file[0]whileTrue:r=(ui.prompt(query+_(' [Ynsfdaq?] '),'(?i)[Ynsfdaq?]?$')or'y').lower()ifr=='?':c=shelve.__doc__.find('y - shelve this change')forlinshelve.__doc__[c:].splitlines():ifl:ui.write(_(l.strip()),'\n')continueelifr=='s':r=resp_file[0]='n'elifr=='f':r=resp_file[0]='y'elifr=='d':r=resp_all[0]='n'elifr=='a':r=resp_all[0]='y'elifr=='q':raiseutil.Abort(_('user quit'))returnrwhilechunks:chunk=chunks.pop()ifisinstance(chunk,header):resp_file=[None]fixoffset=0hdr=''.join(chunk.header)ifhdrinseen:consumefile()continueseen[hdr]=Trueifresp_all[0]isNone:chunk.pretty(ui)r=prompt(_('shelve changes to %s?')%_(' and ').join(map(repr,chunk.files())))ifr=='y':applied[chunk.filename()]=[chunk]ifchunk.allhunks():applied[chunk.filename()]+=consumefile()else:consumefile()else:ifresp_file[0]isNoneandresp_all[0]isNone:chunk.pretty(ui)r=prompt(_('shelve this change to %r?')%chunk.filename())ifr=='y':iffixoffset:chunk=copy.copy(chunk)chunk.toline+=fixoffsetapplied[chunk.filename()].append(chunk)else:fixoffset+=chunk.removed-chunk.addedreturnreduce(operator.add,[hforhinapplied.itervalues()ifh[0].special()orlen(h)>1],[])defrefilterpatch(allchunk,selected):''' return unshelved chunks of files to be shelved '''l=[]fil=[]forcinallchunk:ifisinstance(c,header):iflen(l)>1andl[0]inselected:fil+=ll=[c]elifcnotinselected:l.append(c)iflen(l)>1andl[0]inselected:fil+=lreturnfildefmakebackup(ui,repo,dir,files):try:os.mkdir(dir)exceptOSError,err:iferr.errno!=errno.EEXIST:raisebackups={}forfinfiles:fd,tmpname=tempfile.mkstemp(prefix=f.replace('/','_')+'.',dir=dir)os.close(fd)ui.debug(_('backup %r as %r\n')%(f,tmpname))util.copyfile(repo.wjoin(f),tmpname)backups[f]=tmpnamereturnbackupsdefget_shelve_filename(repo):returnrepo.join('shelve')defshelve(ui,repo,*pats,**opts):'''interactively select changes to set aside If a list of files is omitted, all changes reported by "hg status" will be candidates for shelveing. You will be prompted for whether to shelve changes to each modified file, and for files with multiple changes, for each change to use. For each query, the following responses are possible: y - shelve this change n - skip this change s - skip remaining changes to this file f - shelve remaining changes to this file d - done, skip remaining changes and files a - shelve all changes to all remaining files q - quit, shelveing no changes ? - display help'''ifnothglib.calliffunc(ui.interactive):raiseutil.Abort(_('shelve can only be run interactively'))forced=opts['force']oropts['append']ifos.path.exists(repo.join('shelve'))andnotforced:raiseutil.Abort(_('shelve data already exists'))defshelvefunc(ui,repo,message,match,opts):# If an MQ patch is applied, consider all qdiff changesifhasattr(repo,'mq')andrepo.mq.applied:qtip=repo['.']basenode=qtip.parents()[0].node()else:basenode=repo.dirstate.parents()[0]changes=repo.status(node1=basenode,match=match)[:5]modified,added,removed=changes[:3]files=modified+added+removeddiffopts=mdiff.diffopts(git=True,nodates=True)patch_diff=''.join(patch.diff(repo,basenode,match=match,changes=changes,opts=diffopts))fp=cStringIO.StringIO(patch_diff)ac=parsepatch(fp)fp.close()chunks=filterpatch(ui,ac)rc=refilterpatch(ac,chunks)contenders={}forhinchunks:try:contenders.update(dict.fromkeys(h.files()))exceptAttributeError:passnewfiles=[fforfinfilesiffincontenders]ifnotnewfiles:ui.status(_('no changes to shelve\n'))return0modified=dict.fromkeys(changes[0])backupdir=repo.join('shelve-backups')try:bkfiles=[fforfinnewfilesiffinmodified]backups=makebackup(ui,repo,backupdir,bkfiles)# patch to shelvesp=cStringIO.StringIO()forcinchunks:ifc.filename()inbackups:c.write(sp)doshelve=sp.tell()sp.seek(0)# patch to apply to shelved filesfp=cStringIO.StringIO()forcinrc:ifc.filename()inbackups:c.write(fp)dopatch=fp.tell()fp.seek(0)try:# 3a. apply filtered patch to clean repo (clean)ifbackups:hg.revert(repo,basenode,backups.has_key)# 3b. apply filtered patch to clean repo (apply) if dopatch:
ui.debug(_('applying patch\n'))
ui.debug(fp.getvalue())
- patch.internalpatch(fp, ui, 1, repo.root)
+ patch.internalpatch(fp, ui, 1, repo.root, eolmode=None)
del fp
# 3c. apply filtered patch to clean repo (shelve)
ifdoshelve:ui.debug(_('saving patch to shelve\n'))ifopts['append']:f=repo.opener('shelve',"a")else:f=repo.opener('shelve',"w")f.write(sp.getvalue())delfdelspexcept:try:forrealname,tmpnameinbackups.iteritems():ui.debug(_('restoring %r to %r\n')%(tmpname,realname))util.copyfile(tmpname,repo.wjoin(realname))ui.debug(_('removing shelve file\n'))os.unlink(repo.join('shelve'))exceptOSError:passreturn0finally:try:forrealname,tmpnameinbackups.iteritems():ui.debug(_('removing backup for %r : %r\n')%(realname,tmpname))os.unlink(tmpname)os.rmdir(backupdir)exceptOSError:passfancyopts.fancyopts([],commands.commitopts,opts)returncmdutil.commit(ui,repo,shelvefunc,pats,opts)defunshelve(ui,repo,*pats,**opts):'''restore shelved changes'''try:fp=cStringIO.StringIO()fp.write(repo.opener('shelve').read())ifopts['inspect']:ui.status(fp.getvalue())else:files=[]forchunkinparsepatch(fp):ifisinstance(chunk,header):files+=chunk.files()backupdir=repo.join('shelve-backups')backups=makebackup(ui,repo,backupdir,set(files))ui.debug(_('applying shelved patch\n'))patchdone=0try:try:fp.seek(0)pfiles={}internalpatch(fp,ui,1,repo.root,files=pfiles)patch.updatedir(ui,repo,pfiles)patchdone=1except:ifopts['force']:patchdone=1else:ui.status(_('restoring backup files\n'))forrealname,tmpnameinbackups.iteritems():ui.debug(_('restoring %r to %r\n')%(tmpname,realname))util.copyfile(tmpname,repo.wjoin(realname))finally:try:ui.debug(_('removing backup files\n'))shutil.rmtree(backupdir,True)exceptOSError:passifpatchdone:ui.debug(_('removing shelved patches\n'))os.unlink(repo.join('shelve'))ui.status(_('unshelve completed\n'))exceptIOError:ui.warn(_('nothing to unshelve\n'))cmdtable={"shelve":(shelve,[('A','addremove',None,_('mark new/missing files as added/removed before shelving')),('f','force',None,_('overwrite existing shelve data')),('a','append',None,_('append to existing shelve data')),]+commands.walkopts,_('hg shelve [OPTION]... [FILE]...')),"unshelve":(unshelve,[('i','inspect',None,_('inspect shelved changes only')),('f','force',None,_('proceed even if patches do not unshelve cleanly')),],_('hg unshelve [OPTION]... [FILE]...')),}
Attach a Trello Card
Add a tag
Your session has expired
You are no longer logged in. Please log in and try your request again.
Filter RSS Feed
This RSS feed URL allows you to see the contents of your current filter using any feed reader.
This link includes a special authentication token. If you share the URL with anyone else, they can see this RSS feed's activity. You can disable these tokens when needed.
Your current filter is unsaved; changing it won't affect this RSS feed.