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.
# hglib.py - Mercurial API wrappers for TortoiseHg## Copyright 2007 Steve Borho <steve@borho.org>## This software may be used and distributed according to the terms of the# GNU General Public License version 2, incorporated herein by reference.importosimportsysimportshleximporttimeimporturllibfrommercurialimportui,util,extensions,match,bundlerepo,cmdutilfrommercurialimportdispatch,encoding,templatefilters,filemerge,errorfrommercurialimportdemandimportdemandimport.disable()
try:
# hg >= 1.9
- from mercurial.scmutil import canonpath, user_rcpath
+ from mercurial.scmutil import canonpath, userrcpath+user_rcpath = userrcpathexcept (ImportError, AttributeError):
# hg <= 1.8
from mercurial.util import canonpath, user_rcpath
try:# hg >= 1.9frommercurial.utilimportlocalpathexceptImportError:# hg <= 1.8frommercurial.hgimportlocalpathtry:# hg >= 1.9frommercurial.utilimporthidepassword,removeauthexceptImportError:# hg <= 1.8frommercurial.urlimporthidepassword,removeauthdemandimport.enable()_encoding=encoding.encoding_encodingmode=encoding.encodingmode_fallbackencoding=encoding.fallbackencoding# extensions which can cause problem with TortoiseHg_extensions_blacklist=('color','pager','progress')fromtortoisehg.utilimportpathsfromtortoisehg.util.hgversionimporthgversionfromtortoisehg.util.i18nimport_,ngettextdeftounicode(s):""" Convert the encoding of string from MBCS to Unicode. Based on mercurial.util.tolocal(). Return 'unicode' type string. """ifsisNone:returnNoneifisinstance(s,unicode):returnsforein('utf-8',_encoding):try:returns.decode(e,'strict')exceptUnicodeDecodeError:passreturns.decode(_fallbackencoding,'replace')deffromunicode(s,errors='strict'):""" Convert the encoding of string from Unicode to MBCS. Return 'str' type string. If you don't want an exception for conversion failure, specify errors='replace'. """ifsisNone:returnNones=unicode(s)# s can be QtCore.QStringforencin(_encoding,_fallbackencoding):try:returns.encode(enc)exceptUnicodeEncodeError:passreturns.encode(_encoding,errors)# last ditchdeftoutf(s):""" Convert the encoding of string from MBCS to UTF-8. Return 'str' type string. """ifsisNone:returnNonereturntounicode(s).encode('utf-8').replace('\0','')deffromutf(s):""" Convert the encoding of string from UTF-8 to MBCS Return 'str' type string. """ifsisNone:returnNonetry:returns.decode('utf-8').encode(_encoding)except(UnicodeDecodeError,UnicodeEncodeError):passtry:returns.decode('utf-8').encode(_fallbackencoding)except(UnicodeDecodeError,UnicodeEncodeError):passu=s.decode('utf-8','replace')# last ditchreturnu.encode(_encoding,'replace')_tabwidth=Nonedefgettabwidth(ui):global_tabwidthif_tabwidthisnotNone:return_tabwidthtabwidth=ui.config('tortoisehg','tabwidth')try:tabwidth=int(tabwidth)iftabwidth<1ortabwidth>16:tabwidth=0except(ValueError,TypeError):tabwidth=0_tabwidth=tabwidthreturntabwidth_maxdiff=Nonedefgetmaxdiffsize(ui):global_maxdiffif_maxdiffisnotNone:return_maxdiffmaxdiff=ui.config('tortoisehg','maxdiff')try:maxdiff=int(maxdiff)ifmaxdiff<1:maxdiff=sys.maxintexcept(ValueError,TypeError):maxdiff=1024# 1MB by default_maxdiff=maxdiff*1024return_maxdiff_deadbranch=Nonedefgetdeadbranch(ui):'''return a list of dead branch names in UTF-8'''global_deadbranchif_deadbranchisNone:db=toutf(ui.config('tortoisehg','deadbranch',''))dblist=[b.strip()forbindb.split(',')]_deadbranch=dblistreturn_deadbranchdefgetlivebranch(repo):'''return a list of live branch names in UTF-8'''lives=[]deads=getdeadbranch(repo.ui)cl=repo.changelogforbranch,headsinrepo.branchmap().iteritems():# branch encoded in UTF-8ifbranchindeads:# ignore branch names in tortoisehg.deadbranchcontinuebheads=[hforhinheadsif('close'notincl.read(h)[5])]ifnotbheads:# ignore branches with all heads closedcontinuelives.append(branch.replace('\0',''))returnlivesdefgetlivebheads(repo):'''return a list of revs of live branch heads'''bheads=[]forb,lsinrepo.branchmap().iteritems():bheads+=[repo[x]forxinls]heads=[x.rev()forxinbheadsifnotx.extra().get('close')]heads.sort()heads.reverse()returnheads_hidetags=Nonedefgethidetags(ui):global_hidetagsif_hidetagsisNone:tags=toutf(ui.config('tortoisehg','hidetags',''))taglist=[t.strip()fortintags.split()]_hidetags=taglistreturn_hidetagsdefgetfilteredtags(repo):filtered=[]hides=gethidetags(repo.ui)fortaginlist(repo.tags()):iftagnotinhides:filtered.append(tag)returnfiltereddefgetrawctxtags(changectx):'''Returns the tags for changectx, converted to UTF-8 but unfiltered for hidden tags'''value=[toutf(tag)fortaginchangectx.tags()]iflen(value)==0:returnNonereturnvaluedefgetctxtags(changectx):'''Returns all unhidden tags for changectx, converted to UTF-8'''value=getrawctxtags(changectx)ifvalue:htlist=gethidetags(changectx._repo.ui)tags=[tagfortaginvalueiftagnotinhtlist]iflen(tags)==0:returnNonereturntagsreturnNonedefgetmqpatchtags(repo):'''Returns all tag names used by MQ patches, or []'''ifhasattr(repo,'mq'):repo.mq.parse_series()returnrepo.mq.series[:]else:return[]defgetcurrentqqueue(repo):"""Return the name of the current patch queue."""ifnothasattr(repo,'mq'):returnNonecur=os.path.basename(repo.mq.path)ifcur.startswith('patches-'):cur=cur[8:]returncurdefdiffexpand(line):'Expand tabs in a line of diff/patch text'if_tabwidthisNone:gettabwidth(ui.ui())ifnot_tabwidthorlen(line)<2:returnlinereturnline[0]+line[1:].expandtabs(_tabwidth)_fontconfig=Nonedefgetfontconfig(_ui=None):global_fontconfigif_fontconfigisNone:if_uiisNone:_ui=ui.ui()# defaults_fontconfig={'fontcomment':'monospace 10','fontdiff':'monospace 10','fontlist':'sans 9','fontlog':'monospace 10'}# overwrite defaults with configured valuesforname,valin_ui.configitems('gtools'):ifvalandname.startswith('font'):_fontconfig[name]=valreturn_fontconfigdefinvalidaterepo(repo):repo.dirstate.invalidate()forattrin('_bookmarks','_bookmarkcurrent'):ifattrinrepo.__dict__:delattr(repo,attr)ifisinstance(repo,bundlerepo.bundlerepository):# Work around a bug in hg-1.3. repo.invalidate() breaks# overlay bundlereposreturnrepo.invalidate()if'mq'inrepo.__dict__:#do not create if it does not existrepo.mq.invalidate()defenabledextensions():"""Return the {name: shortdesc} dict of enabled extensions shortdesc is in local encoding. """returnextensions.enabled()[0]defallextensions():"""Return the {name: shortdesc} dict of known extensions shortdesc is in local encoding. """enabledexts=enabledextensions()disabledexts=extensions.disabled()[0]exts=(disabledextsor{}).copy()exts.update(enabledexts)returnextsdefvalidateextensions(enabledexts):"""Report extensions which should be disabled Returns the dict {name: message} of extensions expected to be disabled. message is 'utf-8'-encoded string. """exts={}ifos.name!='posix':exts['inotify']=_('inotify is not supported on this platform')if'win32text'inenabledexts:exts['eol']=_('eol is incompatible with win32text')if'eol'inenabledexts:exts['win32text']=_('win32text is incompatible with eol')if'perfarce'inenabledexts:exts['hgsubversion']=_('hgsubversion is incompatible with perfarce')if'hgsubversion'inenabledexts:exts['perfarce']=_('perfarce is incompatible with hgsubversion')returnextsdefloadextension(ui,name):# Between Mercurial revisions 1.2 and 1.3, extensions.load() stopped# calling uisetup() after loading an extension. This could do# unexpected things if you use an hg version < 1.3extensions.load(ui,name,None)mod=extensions.find(name)uisetup=getattr(mod,'uisetup',None)ifuisetup:uisetup(ui)def_loadextensionwithblacklist(orig,ui,name,path):ifname.startswith('hgext.')orname.startswith('hgext/'):shortname=name[6:]else:shortname=nameifshortnamein_extensions_blacklistandnotpath:# only bundled extreturnreturnorig(ui,name,path)defwrapextensionsloader():"""Wrap extensions.load(ui, name) for blacklist to take effect"""extensions.wrapfunction(extensions,'load',_loadextensionwithblacklist)defcanonpaths(list):'Get canonical paths (relative to root) for list of files'# This is a horrible hack. Please remove this when HG acquires a# decent case-folding solution.canonpats=[]cwd=os.getcwd()root=paths.find_root(cwd)forfinlist:try:canonpats.append(canonpath(root,cwd,f))exceptutil.Abort:# Attempt to resolve case folding conflicts.fu=f.upper()cwdu=cwd.upper()iffu.startswith(cwdu):canonpats.append(canonpath(root,cwd,f[len(cwd+os.sep):]))else:# May already be canonicalcanonpats.append(f)returncanonpatsdefescapepath(path):'Before passing a file path to hg API, it may need escaping'p=pathif'['inpor'{'inpor'*'inpor'?'inp:return'path:'+pelse:returnpdefnormpats(pats):'Normalize file patterns'normpats=[]forpatinpats:kind,p=match._patsplit(pat,None)ifkind:normpats.append(pat)else:if'['inpor'{'inpor'*'inpor'?'inp:normpats.append('glob:'+p)else:normpats.append('path:'+p)returnnormpatsdefmergetools(ui,values=None):'returns the configured merge tools and the internal ones'ifvalues==None:values=[]seen=values[:]forkey,valueinui.configitems('merge-tools'):t=key.split('.')[0]iftnotinseen:seen.append(t)# Ensure the tool is installediffilemerge._findtool(ui,t):values.append(t)values.append('internal:merge')values.append('internal:prompt')values.append('internal:dump')values.append('internal:local')values.append('internal:other')values.append('internal:fail')returnvalues_difftools=Nonedefdifftools(ui):global_difftoolsif_difftools:return_difftoolsdeffixup_extdiff(diffopts):if'$child'notindiffopts:diffopts.append('$parent1')diffopts.append('$child')if'$parent2'indiffopts:mergeopts=diffopts[:]diffopts.remove('$parent2')else:mergeopts=[]returndiffopts,mergeoptstools={}forcmd,pathinui.configitems('extdiff'):ifcmd.startswith('cmd.'):cmd=cmd[4:]ifnotpath:path=cmddiffopts=ui.config('extdiff','opts.'+cmd,'')diffopts=shlex.split(diffopts)diffopts,mergeopts=fixup_extdiff(diffopts)tools[cmd]=[path,diffopts,mergeopts]elifcmd.startswith('opts.'):continueelse:# command = path optsifpath:diffopts=shlex.split(path)path=diffopts.pop(0)else:path,diffopts=cmd,[]diffopts,mergeopts=fixup_extdiff(diffopts)tools[cmd]=[path,diffopts,mergeopts]mt=[]mergetools(ui,mt)fortinmt:ift.startswith('internal:'):continuedopts=ui.config('merge-tools',t+'.diffargs','')mopts=ui.config('merge-tools',t+'.diff3args','')dopts,mopts=shlex.split(dopts),shlex.split(mopts)tools[t]=[filemerge._findtool(ui,t),dopts,mopts]_difftools=toolsreturntoolsdefhgcmd_toq(q,label,args):''' Run an hg command in a background thread, pipe all output to a Queue object. Assumes command is completely noninteractive. '''classQui(ui.ui):def__init__(self,src=None):super(Qui,self).__init__(src)self.setconfig('ui','interactive','off')defwrite(self,*args,**opts):ifself._buffers:self._buffers[-1].extend([str(a)forainargs])else:forainargs:iflabel:q.put((str(a),opts.get('label','')))else:q.put(str(a))defplain(self):returnTrueu=Qui()oldterm=os.environ.get('TERM')os.environ['TERM']='dumb'ret=dispatch._dispatch(u,list(args))ifoldterm:os.environ['TERM']=oldtermreturnretdefget_reponame(repo):ifrepo.ui.config('tortoisehg','fullpath',False):name=repo.rootelifrepo.ui.config('web','name',False):name=repo.ui.config('web','name')else:name=os.path.basename(repo.root)returntoutf(name)defdisplaytime(date):returnutil.datestr(date,'%Y-%m-%d %H:%M:%S %1%2')defutctime(date):returntime.strftime("%Y-%m-%d %H:%M:%S",time.gmtime(date[0]))agescales=[((lambdan:ngettext("%d year","%d years",n)),3600*24*365),((lambdan:ngettext("%d month","%d months",n)),3600*24*30),((lambdan:ngettext("%d week","%d weeks",n)),3600*24*7),((lambdan:ngettext("%d day","%d days",n)),3600*24),((lambdan:ngettext("%d hour","%d hours",n)),3600),((lambdan:ngettext("%d minute","%d minutes",n)),60),((lambdan:ngettext("%d second","%d seconds",n)),1),]defage(date):'''turn a (timestamp, tzoff) tuple into an age string.'''# This is i18n-ed version of mercurial.templatefilters.age().now=time.time()then=date[0]ifthen>now:return_('in the future')delta=int(now-then)ifdelta==0:return_('now')ifdelta>agescales[0][1]*2:returnutil.shortdate(date)fort,sinagescales:n=delta//sifn>=2ors==1:returnt(n)%ndefusername(user):author=templatefilters.person(user)ifnotauthor:author=util.shortuser(user)returnauthordefuser(ctx):''' Get the username of the change context. Does not abort and just returns an empty string if ctx is a working context and no username has been set in mercurial's config. '''try:user=ctx.user()excepterror.Abort:ifctx._revisnotNone:raise# ctx is a working context and probably no username has# been configured in mercurial's configuser=''returnuserdefget_revision_desc(fctx,curpath=None):"""return the revision description as a string"""author=tounicode(username(fctx.user()))rev=fctx.linkrev()# If the source path matches the current path, don't bother including it.ifcurpathandcurpath==fctx.path():source=''else:source='(%s)'%fctx.path()date=age(fctx.date())l=tounicode(fctx.description()).replace('\0','').splitlines()summary=landl[0]or''return'%s@%s%s:%s "%s"'%(author,rev,source,date,summary)defvalidate_synch_path(path,repo):''' Validate the path that must be used to sync operations (pull, push, outgoing and incoming) '''return_path=pathforalias,path_auxinrepo.ui.configitems('paths'):ifpath==alias:return_path=path_auxelifpath==hidepassword(path_aux):return_path=path_auxreturnreturn_pathdefis_rev_current(repo,rev):''' Returns True if the revision indicated by 'rev' is the current working directory parent. If rev is '' or None, it is assumed to mean 'tip'. '''ifrevin('',None):rev='tip'rev=repo.lookup(rev)parents=repo.parents()iflen(parents)>1:returnFalsereturnrev==parents[0].node()defexport(repo,revs,template='hg-%h.patch',fp=None,switch_parent=False,opts=None):''' export changesets as hg patches. Mercurial moved patch.export to cmdutil.export after version 1.5 (change e764f24a45ee in mercurial). '''try:returncmdutil.export(repo,revs,template,fp,switch_parent,opts)exceptAttributeError:frommercurialimportpatchreturnpatch.export(repo,revs,template,fp,switch_parent,opts)defgetDeepestSubrepoContainingFile(wfile,ctx):""" Given a filename and context, get the deepest subrepo that contains the file Also return the corresponding subrepo context and the filename relative to its containing subrepo """ifwfileinctx.manifest():return'',wfile,ctxforwsubinctx.substate:ifwfile.startswith(wsub):srev=ctx.substate[wsub][1]stype=ctx.substate[wsub][2]ifstype!='hg':continueifnotos.path.exists(ctx._repo.wjoin(wsub)):# Maybe the repository does not exist in the working copy?continuetry:sctx=ctx.sub(wsub)._repo[srev]except:# The selected revision does not exist in the working copycontinuewfileinsub=wfile[len(wsub)+1:]ifwfileinsubinsctx.substateorwfileinsubinsctx.manifest():returnwsub,wfileinsub,sctxelse:wsubsub,wfileinsub,sctx= \
getDeepestSubrepoContainingFile(wfileinsub,sctx)ifwsubsubisNone:returnNone,wfile,ctxelse:returnos.path.join(wsub,wsubsub),wfileinsub,sctxreturnNone,wfile,ctxdefnetlocsplit(netloc):'''split [user[:passwd]@]host[:port] into 4-tuple.'''a=netloc.find('@')ifa==-1:user,passwd=None,Noneelse:userpass,netloc=netloc[:a],netloc[a+1:]c=userpass.find(':')ifc==-1:user,passwd=urllib.unquote(userpass),Noneelse:user=urllib.unquote(userpass[:c])passwd=urllib.unquote(userpass[c+1:])c=netloc.find(':')ifc==-1:host,port=netloc,Noneelse:host,port=netloc[:c],netloc[c+1:]returnhost,port,user,passwd
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.